Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

91
vendor/ttf-parser/src/tables/ankr.rs vendored Normal file
View File

@@ -0,0 +1,91 @@
//! An [Anchor Point Table](
//! https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6ankr.html) implementation.
use core::num::NonZeroU16;
use crate::aat;
use crate::parser::{FromData, LazyArray32, Offset, Offset32, Stream};
use crate::GlyphId;
/// An anchor point.
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)]
pub struct Point {
pub x: i16,
pub y: i16,
}
impl FromData for Point {
const SIZE: usize = 4;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(Point {
x: s.read::<i16>()?,
y: s.read::<i16>()?,
})
}
}
/// An [Anchor Point Table](
/// https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6ankr.html).
#[derive(Clone)]
pub struct Table<'a> {
lookup: aat::Lookup<'a>,
// Ideally, Glyphs Data can be represented as an array,
// but Apple's spec doesn't specify that Glyphs Data members have padding or not.
// Meaning we cannot simply iterate over them.
glyphs_data: &'a [u8],
}
impl core::fmt::Debug for Table<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Table {{ ... }}")
}
}
impl<'a> Table<'a> {
/// Parses a table from raw data.
///
/// `number_of_glyphs` is from the `maxp` table.
pub fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let version = s.read::<u16>()?;
if version != 0 {
return None;
}
s.skip::<u16>(); // reserved
// TODO: we should probably check that offset is larger than the header size (8)
let lookup_table = s.read_at_offset32(data)?;
let glyphs_data = s.read_at_offset32(data)?;
Some(Table {
lookup: aat::Lookup::parse(number_of_glyphs, lookup_table)?,
glyphs_data,
})
}
/// Returns a list of anchor points for the specified glyph.
pub fn points(&self, glyph_id: GlyphId) -> Option<LazyArray32<'a, Point>> {
let offset = self.lookup.value(glyph_id)?;
let mut s = Stream::new_at(self.glyphs_data, usize::from(offset))?;
let number_of_points = s.read::<u32>()?;
s.read_array32::<Point>(number_of_points)
}
}
trait StreamExt<'a> {
fn read_at_offset32(&mut self, data: &'a [u8]) -> Option<&'a [u8]>;
}
impl<'a> StreamExt<'a> for Stream<'a> {
fn read_at_offset32(&mut self, data: &'a [u8]) -> Option<&'a [u8]> {
let offset = self.read::<Offset32>()?.to_usize();
data.get(offset..)
}
}

178
vendor/ttf-parser/src/tables/avar.rs vendored Normal file
View File

@@ -0,0 +1,178 @@
//! An [Axis Variations Table](
//! https://docs.microsoft.com/en-us/typography/opentype/spec/avar) implementation.
use core::convert::TryFrom;
use crate::parser::{FromData, LazyArray16, Stream};
use crate::NormalizedCoordinate;
/// An axis value map.
#[derive(Clone, Copy, Debug)]
pub struct AxisValueMap {
/// A normalized coordinate value obtained using default normalization.
pub from_coordinate: i16,
/// The modified, normalized coordinate value.
pub to_coordinate: i16,
}
impl FromData for AxisValueMap {
const SIZE: usize = 4;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(AxisValueMap {
from_coordinate: s.read::<i16>()?,
to_coordinate: s.read::<i16>()?,
})
}
}
/// A list of segment maps.
///
/// Can be empty.
///
/// The internal data layout is not designed for random access,
/// therefore we're not providing the `get()` method and only an iterator.
#[derive(Clone, Copy)]
pub struct SegmentMaps<'a> {
count: u16,
data: &'a [u8],
}
impl<'a> SegmentMaps<'a> {
/// Returns the number of segments.
pub fn len(&self) -> u16 {
self.count
}
/// Checks if there are any segments.
pub fn is_empty(&self) -> bool {
self.count == 0
}
}
impl core::fmt::Debug for SegmentMaps<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "SegmentMaps {{ ... }}")
}
}
impl<'a> IntoIterator for SegmentMaps<'a> {
type Item = LazyArray16<'a, AxisValueMap>;
type IntoIter = SegmentMapsIter<'a>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
SegmentMapsIter {
stream: Stream::new(self.data),
}
}
}
/// An iterator over maps.
#[allow(missing_debug_implementations)]
pub struct SegmentMapsIter<'a> {
stream: Stream<'a>,
}
impl<'a> Iterator for SegmentMapsIter<'a> {
type Item = LazyArray16<'a, AxisValueMap>;
fn next(&mut self) -> Option<Self::Item> {
let count = self.stream.read::<u16>()?;
self.stream.read_array16::<AxisValueMap>(count)
}
}
/// An [Axis Variations Table](
/// https://docs.microsoft.com/en-us/typography/opentype/spec/avar).
#[derive(Clone, Copy, Debug)]
pub struct Table<'a> {
/// The segment maps array — one segment map for each axis
/// in the order of axes specified in the `fvar` table.
pub segment_maps: SegmentMaps<'a>,
}
impl<'a> Table<'a> {
/// Parses a table from raw data.
pub fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let version = s.read::<u32>()?;
if version != 0x00010000 {
return None;
}
s.skip::<u16>(); // reserved
Some(Self {
segment_maps: SegmentMaps {
// TODO: check that `axisCount` is the same as in `fvar`?
count: s.read::<u16>()?,
data: s.tail()?,
},
})
}
/// Maps coordinates.
pub fn map_coordinates(&self, coordinates: &mut [NormalizedCoordinate]) -> Option<()> {
if usize::from(self.segment_maps.count) != coordinates.len() {
return None;
}
for (map, coord) in self.segment_maps.into_iter().zip(coordinates) {
*coord = NormalizedCoordinate::from(map_value(&map, coord.0)?);
}
Some(())
}
}
fn map_value(map: &LazyArray16<AxisValueMap>, value: i16) -> Option<i16> {
// This code is based on harfbuzz implementation.
if map.is_empty() {
return Some(value);
} else if map.len() == 1 {
let record = map.get(0)?;
return Some(value - record.from_coordinate + record.to_coordinate);
}
let record_0 = map.get(0)?;
if value <= record_0.from_coordinate {
return Some(value - record_0.from_coordinate + record_0.to_coordinate);
}
let mut i = 1;
while i < map.len() && value > map.get(i)?.from_coordinate {
i += 1;
}
if i == map.len() {
i -= 1;
}
let record_curr = map.get(i)?;
let curr_from = record_curr.from_coordinate;
let curr_to = record_curr.to_coordinate;
if value >= curr_from {
return Some(value - curr_from + curr_to);
}
let record_prev = map.get(i - 1)?;
let prev_from = record_prev.from_coordinate;
let prev_to = record_prev.to_coordinate;
if prev_from == curr_from {
return Some(prev_to);
}
let curr_from = i32::from(curr_from);
let curr_to = i32::from(curr_to);
let prev_from = i32::from(prev_from);
let prev_to = i32::from(prev_to);
let denom = curr_from - prev_from;
let k = (curr_to - prev_to) * (i32::from(value) - prev_from) + denom / 2;
let value = prev_to + k / denom;
i16::try_from(value).ok()
}

132
vendor/ttf-parser/src/tables/cbdt.rs vendored Normal file
View File

@@ -0,0 +1,132 @@
//! A [Color Bitmap Data Table](
//! https://docs.microsoft.com/en-us/typography/opentype/spec/cbdt) implementation.
use crate::cblc::{self, BitmapDataFormat, Metrics, MetricsFormat};
use crate::parser::{NumFrom, Stream};
use crate::{GlyphId, RasterGlyphImage, RasterImageFormat};
/// A [Color Bitmap Data Table](
/// https://docs.microsoft.com/en-us/typography/opentype/spec/cbdt).
///
/// EBDT and bdat also share the same structure, so this is re-used for them.
#[derive(Clone, Copy)]
pub struct Table<'a> {
locations: cblc::Table<'a>,
data: &'a [u8],
}
impl<'a> Table<'a> {
/// Parses a table from raw data.
pub fn parse(locations: cblc::Table<'a>, data: &'a [u8]) -> Option<Self> {
Some(Self { locations, data })
}
/// Returns a raster image for the glyph.
pub fn get(&self, glyph_id: GlyphId, pixels_per_em: u16) -> Option<RasterGlyphImage<'a>> {
let location = self.locations.get(glyph_id, pixels_per_em)?;
let mut s = Stream::new_at(self.data, location.offset)?;
let metrics = match location.format.metrics {
MetricsFormat::Small => {
let height = s.read::<u8>()?;
let width = s.read::<u8>()?;
let bearing_x = s.read::<i8>()?;
let bearing_y = s.read::<i8>()?;
s.skip::<u8>(); // advance
Metrics {
x: bearing_x,
y: bearing_y,
width,
height,
}
}
MetricsFormat::Big => {
let height = s.read::<u8>()?;
let width = s.read::<u8>()?;
let hor_bearing_x = s.read::<i8>()?;
let hor_bearing_y = s.read::<i8>()?;
s.skip::<u8>(); // hor_advance
s.skip::<i8>(); // ver_bearing_x
s.skip::<i8>(); // ver_bearing_y
s.skip::<u8>(); // ver_advance
Metrics {
x: hor_bearing_x,
y: hor_bearing_y,
width,
height,
}
}
MetricsFormat::Shared => location.metrics,
};
match location.format.data {
BitmapDataFormat::ByteAligned { bit_depth } => {
let row_len = (u32::from(metrics.width) * u32::from(bit_depth) + 7) / 8;
let data_len = row_len * u32::from(metrics.height);
let data = s.read_bytes(usize::num_from(data_len))?;
Some(RasterGlyphImage {
x: i16::from(metrics.x),
// `y` in CBDT is a bottom bound, not top one.
y: i16::from(metrics.y) - i16::from(metrics.height),
width: u16::from(metrics.width),
height: u16::from(metrics.height),
pixels_per_em: location.ppem,
format: match bit_depth {
1 => RasterImageFormat::BitmapMono,
2 => RasterImageFormat::BitmapGray2,
4 => RasterImageFormat::BitmapGray4,
8 => RasterImageFormat::BitmapGray8,
32 => RasterImageFormat::BitmapPremulBgra32,
_ => return None,
},
data,
})
}
BitmapDataFormat::BitAligned { bit_depth } => {
let data_len = {
let w = u32::from(metrics.width);
let h = u32::from(metrics.height);
let d = u32::from(bit_depth);
(w * h * d + 7) / 8
};
let data = s.read_bytes(usize::num_from(data_len))?;
Some(RasterGlyphImage {
x: i16::from(metrics.x),
// `y` in CBDT is a bottom bound, not top one.
y: i16::from(metrics.y) - i16::from(metrics.height),
width: u16::from(metrics.width),
height: u16::from(metrics.height),
pixels_per_em: location.ppem,
format: match bit_depth {
1 => RasterImageFormat::BitmapMonoPacked,
2 => RasterImageFormat::BitmapGray2Packed,
4 => RasterImageFormat::BitmapGray4Packed,
8 => RasterImageFormat::BitmapGray8,
32 => RasterImageFormat::BitmapPremulBgra32,
_ => return None,
},
data,
})
}
BitmapDataFormat::PNG => {
let data_len = s.read::<u32>()?;
let data = s.read_bytes(usize::num_from(data_len))?;
Some(RasterGlyphImage {
x: i16::from(metrics.x),
// `y` in CBDT is a bottom bound, not top one.
y: i16::from(metrics.y) - i16::from(metrics.height),
width: u16::from(metrics.width),
height: u16::from(metrics.height),
pixels_per_em: location.ppem,
format: RasterImageFormat::PNG,
data,
})
}
}
}
}
impl core::fmt::Debug for Table<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Table {{ ... }}")
}
}

285
vendor/ttf-parser/src/tables/cblc.rs vendored Normal file
View File

@@ -0,0 +1,285 @@
//! A [Color Bitmap Location Table](
//! https://docs.microsoft.com/en-us/typography/opentype/spec/cblc) implementation.
use crate::parser::{FromData, NumFrom, Offset, Offset16, Offset32, Stream};
use crate::GlyphId;
#[derive(Clone, Copy, PartialEq, Debug)]
pub(crate) struct BitmapFormat {
pub metrics: MetricsFormat,
pub data: BitmapDataFormat,
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub(crate) enum MetricsFormat {
Small,
Big,
Shared,
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub(crate) enum BitmapDataFormat {
ByteAligned { bit_depth: u8 },
BitAligned { bit_depth: u8 },
PNG,
}
#[derive(Clone, Copy, Default, Debug)]
pub(crate) struct Metrics {
pub x: i8,
pub y: i8,
pub width: u8,
pub height: u8,
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct Location {
pub format: BitmapFormat,
pub offset: usize,
pub metrics: Metrics,
pub ppem: u16,
}
#[derive(Clone, Copy)]
struct BitmapSizeTable {
subtable_array_offset: Offset32,
number_of_subtables: u32,
ppem: u16,
bit_depth: u8,
// Many fields are omitted.
}
fn select_bitmap_size_table(
glyph_id: GlyphId,
pixels_per_em: u16,
mut s: Stream,
) -> Option<BitmapSizeTable> {
let subtable_count = s.read::<u32>()?;
let orig_s = s.clone();
let mut idx = None;
let mut max_ppem = 0;
let mut bit_depth_for_max_ppem = 0;
for i in 0..subtable_count {
// Check that the current subtable contains a provided glyph id.
s.advance(40); // Jump to `start_glyph_index`.
let start_glyph_id = s.read::<GlyphId>()?;
let end_glyph_id = s.read::<GlyphId>()?;
let ppem_x = u16::from(s.read::<u8>()?);
s.advance(1); // ppem_y
let bit_depth = s.read::<u8>()?;
s.advance(1); // flags
if !(start_glyph_id..=end_glyph_id).contains(&glyph_id) {
continue;
}
// Select a best matching subtable based on `pixels_per_em`.
if (pixels_per_em <= ppem_x && ppem_x < max_ppem)
|| (pixels_per_em > max_ppem && ppem_x > max_ppem)
{
idx = Some(usize::num_from(i));
max_ppem = ppem_x;
bit_depth_for_max_ppem = bit_depth;
}
}
let mut s = orig_s;
s.advance(idx? * 48); // 48 is BitmapSize Table size
let subtable_array_offset = s.read::<Offset32>()?;
s.skip::<u32>(); // index_tables_size
let number_of_subtables = s.read::<u32>()?;
Some(BitmapSizeTable {
subtable_array_offset,
number_of_subtables,
ppem: max_ppem,
bit_depth: bit_depth_for_max_ppem,
})
}
#[derive(Clone, Copy)]
struct IndexSubtableInfo {
start_glyph_id: GlyphId,
offset: usize, // absolute offset
}
fn select_index_subtable(
data: &[u8],
size_table: BitmapSizeTable,
glyph_id: GlyphId,
) -> Option<IndexSubtableInfo> {
let mut s = Stream::new_at(data, size_table.subtable_array_offset.to_usize())?;
for _ in 0..size_table.number_of_subtables {
let start_glyph_id = s.read::<GlyphId>()?;
let end_glyph_id = s.read::<GlyphId>()?;
let offset = s.read::<Offset32>()?;
if (start_glyph_id..=end_glyph_id).contains(&glyph_id) {
let offset = size_table.subtable_array_offset.to_usize() + offset.to_usize();
return Some(IndexSubtableInfo {
start_glyph_id,
offset,
});
}
}
None
}
#[derive(Clone, Copy)]
struct GlyphIdOffsetPair {
glyph_id: GlyphId,
offset: Offset16,
}
impl FromData for GlyphIdOffsetPair {
const SIZE: usize = 4;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(GlyphIdOffsetPair {
glyph_id: s.read::<GlyphId>()?,
offset: s.read::<Offset16>()?,
})
}
}
// TODO: rewrite
/// A [Color Bitmap Location Table](
/// https://docs.microsoft.com/en-us/typography/opentype/spec/cblc).
///
/// EBLC and bloc also share the same structure, so this is re-used for them.
#[derive(Clone, Copy)]
pub struct Table<'a> {
data: &'a [u8],
}
impl<'a> Table<'a> {
/// Parses a table from raw data.
pub fn parse(data: &'a [u8]) -> Option<Self> {
Some(Self { data })
}
pub(crate) fn get(&self, glyph_id: GlyphId, pixels_per_em: u16) -> Option<Location> {
let mut s = Stream::new(self.data);
// The CBLC table version is a bit tricky, so we are ignoring it for now.
// The CBLC table is based on EBLC table, which was based on the `bloc` table.
// And before the CBLC table specification was finished, some fonts,
// notably Noto Emoji, have used version 2.0, but the final spec allows only 3.0.
// So there are perfectly valid fonts in the wild, which have an invalid version.
s.skip::<u32>(); // version
let size_table = select_bitmap_size_table(glyph_id, pixels_per_em, s)?;
let info = select_index_subtable(self.data, size_table, glyph_id)?;
let mut s = Stream::new_at(self.data, info.offset)?;
let index_format = s.read::<u16>()?;
let image_format = s.read::<u16>()?;
let mut image_offset = s.read::<Offset32>()?.to_usize();
let bit_depth = size_table.bit_depth;
let image_format = match image_format {
1 => BitmapFormat {
metrics: MetricsFormat::Small,
data: BitmapDataFormat::ByteAligned { bit_depth },
},
2 => BitmapFormat {
metrics: MetricsFormat::Small,
data: BitmapDataFormat::BitAligned { bit_depth },
},
5 => BitmapFormat {
metrics: MetricsFormat::Shared,
data: BitmapDataFormat::BitAligned { bit_depth },
},
6 => BitmapFormat {
metrics: MetricsFormat::Big,
data: BitmapDataFormat::ByteAligned { bit_depth },
},
7 => BitmapFormat {
metrics: MetricsFormat::Big,
data: BitmapDataFormat::BitAligned { bit_depth },
},
17 => BitmapFormat {
metrics: MetricsFormat::Small,
data: BitmapDataFormat::PNG,
},
18 => BitmapFormat {
metrics: MetricsFormat::Big,
data: BitmapDataFormat::PNG,
},
19 => BitmapFormat {
metrics: MetricsFormat::Shared,
data: BitmapDataFormat::PNG,
},
_ => return None, // Invalid format.
};
// TODO: I wasn't able to find fonts with index 4 and 5, so they are untested.
let glyph_diff = glyph_id.0.checked_sub(info.start_glyph_id.0)?;
let mut metrics = Metrics::default();
match index_format {
1 => {
s.advance(usize::from(glyph_diff) * Offset32::SIZE);
let offset = s.read::<Offset32>()?;
image_offset += offset.to_usize();
}
2 => {
let image_size = s.read::<u32>()?;
image_offset += usize::from(glyph_diff).checked_mul(usize::num_from(image_size))?;
metrics.height = s.read::<u8>()?;
metrics.width = s.read::<u8>()?;
metrics.x = s.read::<i8>()?;
metrics.y = s.read::<i8>()?;
}
3 => {
s.advance(usize::from(glyph_diff) * Offset16::SIZE);
let offset = s.read::<Offset16>()?;
image_offset += offset.to_usize();
}
4 => {
let num_glyphs = s.read::<u32>()?;
let num_glyphs = num_glyphs.checked_add(1)?;
let pairs = s.read_array32::<GlyphIdOffsetPair>(num_glyphs)?;
let pair = pairs.into_iter().find(|pair| pair.glyph_id == glyph_id)?;
image_offset += pair.offset.to_usize();
}
5 => {
let image_size = s.read::<u32>()?;
metrics.height = s.read::<u8>()?;
metrics.width = s.read::<u8>()?;
metrics.x = s.read::<i8>()?;
metrics.y = s.read::<i8>()?;
s.skip::<u8>(); // hor_advance
s.skip::<i8>(); // ver_bearing_x
s.skip::<i8>(); // ver_bearing_y
s.skip::<u8>(); // ver_advance
let num_glyphs = s.read::<u32>()?;
let glyphs = s.read_array32::<GlyphId>(num_glyphs)?;
let (index, _) = glyphs.binary_search(&glyph_id)?;
image_offset = image_offset.checked_add(
usize::num_from(index).checked_mul(usize::num_from(image_size))?,
)?;
}
_ => return None, // Invalid format.
}
Some(Location {
format: image_format,
offset: image_offset,
metrics,
ppem: size_table.ppem,
})
}
}
impl core::fmt::Debug for Table<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Table {{ ... }}")
}
}

View File

@@ -0,0 +1,64 @@
use super::CFFError;
pub struct ArgumentsStack<'a> {
pub data: &'a mut [f32],
pub len: usize,
pub max_len: usize,
}
impl<'a> ArgumentsStack<'a> {
#[inline]
pub fn len(&self) -> usize {
self.len
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
#[inline]
pub fn push(&mut self, n: f32) -> Result<(), CFFError> {
if self.len == self.max_len {
Err(CFFError::ArgumentsStackLimitReached)
} else {
self.data[self.len] = n;
self.len += 1;
Ok(())
}
}
#[inline]
pub fn at(&self, index: usize) -> f32 {
self.data[index]
}
#[inline]
pub fn pop(&mut self) -> f32 {
debug_assert!(!self.is_empty());
self.len -= 1;
self.data[self.len]
}
#[inline]
pub fn reverse(&mut self) {
if self.is_empty() {
return;
}
// Reverse only the actual data and not the whole stack.
let (first, _) = self.data.split_at_mut(self.len);
first.reverse();
}
#[inline]
pub fn clear(&mut self) {
self.len = 0;
}
}
impl core::fmt::Debug for ArgumentsStack<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.debug_list().entries(&self.data[..self.len]).finish()
}
}

1052
vendor/ttf-parser/src/tables/cff/cff1.rs vendored Normal file

File diff suppressed because it is too large Load Diff

564
vendor/ttf-parser/src/tables/cff/cff2.rs vendored Normal file
View File

@@ -0,0 +1,564 @@
//! A [Compact Font Format 2 Table](
//! https://docs.microsoft.com/en-us/typography/opentype/spec/cff2) implementation.
// https://docs.microsoft.com/en-us/typography/opentype/spec/cff2charstr
use core::convert::TryFrom;
use core::ops::Range;
use super::argstack::ArgumentsStack;
use super::charstring::CharStringParser;
use super::dict::DictionaryParser;
use super::index::{parse_index, Index};
use super::{calc_subroutine_bias, conv_subroutine_index, Builder, CFFError};
use crate::parser::{NumFrom, Stream, TryNumFrom};
use crate::var_store::*;
use crate::{GlyphId, NormalizedCoordinate, OutlineBuilder, Rect, RectF};
// https://docs.microsoft.com/en-us/typography/opentype/spec/cff2#7-top-dict-data
// 'Operators in DICT may be preceded by up to a maximum of 513 operands.'
const MAX_OPERANDS_LEN: usize = 513;
// https://docs.microsoft.com/en-us/typography/opentype/spec/cff2charstr#appendix-b-cff2-charstring-implementation-limits
const STACK_LIMIT: u8 = 10;
const MAX_ARGUMENTS_STACK_LEN: usize = 513;
const TWO_BYTE_OPERATOR_MARK: u8 = 12;
// https://docs.microsoft.com/en-us/typography/opentype/spec/cff2charstr#4-charstring-operators
mod operator {
pub const HORIZONTAL_STEM: u8 = 1;
pub const VERTICAL_STEM: u8 = 3;
pub const VERTICAL_MOVE_TO: u8 = 4;
pub const LINE_TO: u8 = 5;
pub const HORIZONTAL_LINE_TO: u8 = 6;
pub const VERTICAL_LINE_TO: u8 = 7;
pub const CURVE_TO: u8 = 8;
pub const CALL_LOCAL_SUBROUTINE: u8 = 10;
pub const VS_INDEX: u8 = 15;
pub const BLEND: u8 = 16;
pub const HORIZONTAL_STEM_HINT_MASK: u8 = 18;
pub const HINT_MASK: u8 = 19;
pub const COUNTER_MASK: u8 = 20;
pub const MOVE_TO: u8 = 21;
pub const HORIZONTAL_MOVE_TO: u8 = 22;
pub const VERTICAL_STEM_HINT_MASK: u8 = 23;
pub const CURVE_LINE: u8 = 24;
pub const LINE_CURVE: u8 = 25;
pub const VV_CURVE_TO: u8 = 26;
pub const HH_CURVE_TO: u8 = 27;
pub const SHORT_INT: u8 = 28;
pub const CALL_GLOBAL_SUBROUTINE: u8 = 29;
pub const VH_CURVE_TO: u8 = 30;
pub const HV_CURVE_TO: u8 = 31;
pub const HFLEX: u8 = 34;
pub const FLEX: u8 = 35;
pub const HFLEX1: u8 = 36;
pub const FLEX1: u8 = 37;
pub const FIXED_16_16: u8 = 255;
}
// https://docs.microsoft.com/en-us/typography/opentype/spec/cff2#table-9-top-dict-operator-entries
mod top_dict_operator {
pub const CHAR_STRINGS_OFFSET: u16 = 17;
pub const VARIATION_STORE_OFFSET: u16 = 24;
pub const FONT_DICT_INDEX_OFFSET: u16 = 1236;
}
// https://docs.microsoft.com/en-us/typography/opentype/spec/cff2#table-10-font-dict-operator-entries
mod font_dict_operator {
pub const PRIVATE_DICT_SIZE_AND_OFFSET: u16 = 18;
}
// https://docs.microsoft.com/en-us/typography/opentype/spec/cff2#table-16-private-dict-operators
mod private_dict_operator {
pub const LOCAL_SUBROUTINES_OFFSET: u16 = 19;
}
#[derive(Clone, Copy, Default)]
struct TopDictData {
char_strings_offset: usize,
font_dict_index_offset: Option<usize>,
variation_store_offset: Option<usize>,
}
fn parse_top_dict(data: &[u8]) -> Option<TopDictData> {
let mut dict_data = TopDictData::default();
let mut operands_buffer = [0.0; MAX_OPERANDS_LEN];
let mut dict_parser = DictionaryParser::new(data, &mut operands_buffer);
while let Some(operator) = dict_parser.parse_next() {
if operator.get() == top_dict_operator::CHAR_STRINGS_OFFSET {
dict_data.char_strings_offset = dict_parser.parse_offset()?;
} else if operator.get() == top_dict_operator::FONT_DICT_INDEX_OFFSET {
dict_data.font_dict_index_offset = dict_parser.parse_offset();
} else if operator.get() == top_dict_operator::VARIATION_STORE_OFFSET {
dict_data.variation_store_offset = dict_parser.parse_offset();
}
}
// Must be set, otherwise there are nothing to parse.
if dict_data.char_strings_offset == 0 {
return None;
}
Some(dict_data)
}
fn parse_font_dict(data: &[u8]) -> Option<Range<usize>> {
let mut private_dict_range = None;
let mut operands_buffer = [0.0; MAX_OPERANDS_LEN];
let mut dict_parser = DictionaryParser::new(data, &mut operands_buffer);
while let Some(operator) = dict_parser.parse_next() {
if operator.get() == font_dict_operator::PRIVATE_DICT_SIZE_AND_OFFSET {
dict_parser.parse_operands()?;
let operands = dict_parser.operands();
if operands.len() == 2 {
let len = usize::try_from(operands[0] as i32).ok()?;
let start = usize::try_from(operands[1] as i32).ok()?;
let end = start.checked_add(len)?;
private_dict_range = Some(start..end);
}
break;
}
}
private_dict_range
}
fn parse_private_dict(data: &[u8]) -> Option<usize> {
let mut subroutines_offset = None;
let mut operands_buffer = [0.0; MAX_OPERANDS_LEN];
let mut dict_parser = DictionaryParser::new(data, &mut operands_buffer);
while let Some(operator) = dict_parser.parse_next() {
if operator.get() == private_dict_operator::LOCAL_SUBROUTINES_OFFSET {
dict_parser.parse_operands()?;
let operands = dict_parser.operands();
if operands.len() == 1 {
subroutines_offset = usize::try_from(operands[0] as i32).ok();
}
break;
}
}
subroutines_offset
}
/// CFF2 allows up to 65535 scalars, but an average font will have 3-5.
/// So 64 is more than enough.
const SCALARS_MAX: u8 = 64;
#[derive(Clone, Copy)]
pub(crate) struct Scalars {
d: [f32; SCALARS_MAX as usize], // 256B
len: u8,
}
impl Default for Scalars {
fn default() -> Self {
Scalars {
d: [0.0; SCALARS_MAX as usize],
len: 0,
}
}
}
impl Scalars {
pub fn len(&self) -> u8 {
self.len
}
pub fn clear(&mut self) {
self.len = 0;
}
pub fn at(&self, i: u8) -> f32 {
if i < self.len {
self.d[usize::from(i)]
} else {
0.0
}
}
pub fn push(&mut self, n: f32) -> Option<()> {
if self.len < SCALARS_MAX {
self.d[usize::from(self.len)] = n;
self.len += 1;
Some(())
} else {
None
}
}
}
struct CharStringParserContext<'a> {
metadata: &'a Table<'a>,
coordinates: &'a [NormalizedCoordinate],
scalars: Scalars,
had_vsindex: bool,
had_blend: bool,
stems_len: u32,
}
impl CharStringParserContext<'_> {
fn update_scalars(&mut self, index: u16) -> Result<(), CFFError> {
self.scalars.clear();
let indices = self
.metadata
.item_variation_store
.region_indices(index)
.ok_or(CFFError::InvalidItemVariationDataIndex)?;
for index in indices {
let scalar = self
.metadata
.item_variation_store
.regions
.evaluate_region(index, self.coordinates);
self.scalars
.push(scalar)
.ok_or(CFFError::BlendRegionsLimitReached)?;
}
Ok(())
}
}
fn parse_char_string(
data: &[u8],
metadata: &Table,
coordinates: &[NormalizedCoordinate],
builder: &mut dyn OutlineBuilder,
) -> Result<Rect, CFFError> {
let mut ctx = CharStringParserContext {
metadata,
coordinates,
scalars: Scalars::default(),
had_vsindex: false,
had_blend: false,
stems_len: 0,
};
// Load scalars at default index.
ctx.update_scalars(0)?;
let mut inner_builder = Builder {
builder,
bbox: RectF::new(),
};
let stack = ArgumentsStack {
data: &mut [0.0; MAX_ARGUMENTS_STACK_LEN], // 2052B
len: 0,
max_len: MAX_ARGUMENTS_STACK_LEN,
};
let mut parser = CharStringParser {
stack,
builder: &mut inner_builder,
x: 0.0,
y: 0.0,
has_move_to: false,
is_first_move_to: true,
width_only: false,
};
_parse_char_string(&mut ctx, data, 0, &mut parser)?;
// let _ = _parse_char_string(&mut ctx, data, 0.0, 0.0, &mut stack, 0, &mut inner_builder)?;
let bbox = parser.builder.bbox;
// Check that bbox was changed.
if bbox.is_default() {
return Err(CFFError::ZeroBBox);
}
bbox.to_rect().ok_or(CFFError::BboxOverflow)
}
fn _parse_char_string(
ctx: &mut CharStringParserContext,
char_string: &[u8],
depth: u8,
p: &mut CharStringParser,
) -> Result<(), CFFError> {
let mut s = Stream::new(char_string);
while !s.at_end() {
let op = s.read::<u8>().ok_or(CFFError::ReadOutOfBounds)?;
match op {
0 | 2 | 9 | 11 | 13 | 14 | 17 => {
// Reserved.
return Err(CFFError::InvalidOperator);
}
operator::HORIZONTAL_STEM
| operator::VERTICAL_STEM
| operator::HORIZONTAL_STEM_HINT_MASK
| operator::VERTICAL_STEM_HINT_MASK => {
// y dy {dya dyb}* hstem
// x dx {dxa dxb}* vstem
// y dy {dya dyb}* hstemhm
// x dx {dxa dxb}* vstemhm
ctx.stems_len += p.stack.len() as u32 >> 1;
// We are ignoring the hint operators.
p.stack.clear();
}
operator::VERTICAL_MOVE_TO => {
p.parse_vertical_move_to(0)?;
}
operator::LINE_TO => {
p.parse_line_to()?;
}
operator::HORIZONTAL_LINE_TO => {
p.parse_horizontal_line_to()?;
}
operator::VERTICAL_LINE_TO => {
p.parse_vertical_line_to()?;
}
operator::CURVE_TO => {
p.parse_curve_to()?;
}
operator::CALL_LOCAL_SUBROUTINE => {
if p.stack.is_empty() {
return Err(CFFError::InvalidArgumentsStackLength);
}
if depth == STACK_LIMIT {
return Err(CFFError::NestingLimitReached);
}
let subroutine_bias = calc_subroutine_bias(ctx.metadata.local_subrs.len());
let index = conv_subroutine_index(p.stack.pop(), subroutine_bias)?;
let char_string = ctx
.metadata
.local_subrs
.get(index)
.ok_or(CFFError::InvalidSubroutineIndex)?;
_parse_char_string(ctx, char_string, depth + 1, p)?;
}
TWO_BYTE_OPERATOR_MARK => {
// flex
let op2 = s.read::<u8>().ok_or(CFFError::ReadOutOfBounds)?;
match op2 {
operator::HFLEX => p.parse_hflex()?,
operator::FLEX => p.parse_flex()?,
operator::HFLEX1 => p.parse_hflex1()?,
operator::FLEX1 => p.parse_flex1()?,
_ => return Err(CFFError::UnsupportedOperator),
}
}
operator::VS_INDEX => {
// |- ivs vsindex (15) |-
// `vsindex` must precede the first `blend` operator, and may occur only once.
if ctx.had_blend || ctx.had_vsindex {
// TODO: maybe add a custom error
return Err(CFFError::InvalidOperator);
}
if p.stack.len() != 1 {
return Err(CFFError::InvalidArgumentsStackLength);
}
let index = u16::try_num_from(p.stack.pop())
.ok_or(CFFError::InvalidItemVariationDataIndex)?;
ctx.update_scalars(index)?;
ctx.had_vsindex = true;
p.stack.clear();
}
operator::BLEND => {
// num(0)..num(n-1), delta(0,0)..delta(k-1,0),
// delta(0,1)..delta(k-1,1) .. delta(0,n-1)..delta(k-1,n-1)
// n blend (16) val(0)..val(n-1)
ctx.had_blend = true;
let n = u16::try_num_from(p.stack.pop())
.ok_or(CFFError::InvalidNumberOfBlendOperands)?;
let k = ctx.scalars.len();
let len = usize::from(n) * (usize::from(k) + 1);
if p.stack.len() < len {
return Err(CFFError::InvalidArgumentsStackLength);
}
let start = p.stack.len() - len;
for i in (0..n).rev() {
for j in 0..k {
let delta = p.stack.pop();
p.stack.data[start + usize::from(i)] += delta * ctx.scalars.at(k - j - 1);
}
}
}
operator::HINT_MASK | operator::COUNTER_MASK => {
ctx.stems_len += p.stack.len() as u32 >> 1;
s.advance(usize::num_from((ctx.stems_len + 7) >> 3));
// We are ignoring the hint operators.
p.stack.clear();
}
operator::MOVE_TO => {
p.parse_move_to(0)?;
}
operator::HORIZONTAL_MOVE_TO => {
p.parse_horizontal_move_to(0)?;
}
operator::CURVE_LINE => {
p.parse_curve_line()?;
}
operator::LINE_CURVE => {
p.parse_line_curve()?;
}
operator::VV_CURVE_TO => {
p.parse_vv_curve_to()?;
}
operator::HH_CURVE_TO => {
p.parse_hh_curve_to()?;
}
operator::SHORT_INT => {
let n = s.read::<i16>().ok_or(CFFError::ReadOutOfBounds)?;
p.stack.push(f32::from(n))?;
}
operator::CALL_GLOBAL_SUBROUTINE => {
if p.stack.is_empty() {
return Err(CFFError::InvalidArgumentsStackLength);
}
if depth == STACK_LIMIT {
return Err(CFFError::NestingLimitReached);
}
let subroutine_bias = calc_subroutine_bias(ctx.metadata.global_subrs.len());
let index = conv_subroutine_index(p.stack.pop(), subroutine_bias)?;
let char_string = ctx
.metadata
.global_subrs
.get(index)
.ok_or(CFFError::InvalidSubroutineIndex)?;
_parse_char_string(ctx, char_string, depth + 1, p)?;
}
operator::VH_CURVE_TO => {
p.parse_vh_curve_to()?;
}
operator::HV_CURVE_TO => {
p.parse_hv_curve_to()?;
}
32..=246 => {
p.parse_int1(op)?;
}
247..=250 => {
p.parse_int2(op, &mut s)?;
}
251..=254 => {
p.parse_int3(op, &mut s)?;
}
operator::FIXED_16_16 => {
p.parse_fixed(&mut s)?;
}
}
}
Ok(())
}
/// A [Compact Font Format 2 Table](
/// https://docs.microsoft.com/en-us/typography/opentype/spec/cff2).
#[derive(Clone, Copy, Default)]
pub struct Table<'a> {
global_subrs: Index<'a>,
local_subrs: Index<'a>,
char_strings: Index<'a>,
item_variation_store: ItemVariationStore<'a>,
}
impl<'a> Table<'a> {
/// Parses a table from raw data.
pub fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
// Parse Header.
let major = s.read::<u8>()?;
s.skip::<u8>(); // minor
let header_size = s.read::<u8>()?;
let top_dict_length = s.read::<u16>()?;
if major != 2 {
return None;
}
// Jump to Top DICT. It's not necessarily right after the header.
if header_size > 5 {
s.advance(usize::from(header_size) - 5);
}
let top_dict_data = s.read_bytes(usize::from(top_dict_length))?;
let top_dict = parse_top_dict(top_dict_data)?;
let mut metadata = Self::default();
// Parse Global Subroutines INDEX.
metadata.global_subrs = parse_index::<u32>(&mut s)?;
metadata.char_strings = {
let mut s = Stream::new_at(data, top_dict.char_strings_offset)?;
parse_index::<u32>(&mut s)?
};
if let Some(offset) = top_dict.variation_store_offset {
let mut s = Stream::new_at(data, offset)?;
s.skip::<u16>(); // length
metadata.item_variation_store = ItemVariationStore::parse(s)?;
}
// TODO: simplify
if let Some(offset) = top_dict.font_dict_index_offset {
let mut s = Stream::new_at(data, offset)?;
'outer: for font_dict_data in parse_index::<u32>(&mut s)? {
if let Some(private_dict_range) = parse_font_dict(font_dict_data) {
// 'Private DICT size and offset, from start of the CFF2 table.'
let private_dict_data = data.get(private_dict_range.clone())?;
if let Some(subroutines_offset) = parse_private_dict(private_dict_data) {
// 'The local subroutines offset is relative to the beginning
// of the Private DICT data.'
if let Some(start) =
private_dict_range.start.checked_add(subroutines_offset)
{
let data = data.get(start..data.len())?;
let mut s = Stream::new(data);
metadata.local_subrs = parse_index::<u32>(&mut s)?;
break 'outer;
}
}
}
}
}
Some(metadata)
}
/// Outlines a glyph.
pub fn outline(
&self,
coordinates: &[NormalizedCoordinate],
glyph_id: GlyphId,
builder: &mut dyn OutlineBuilder,
) -> Result<Rect, CFFError> {
let data = self
.char_strings
.get(u32::from(glyph_id.0))
.ok_or(CFFError::NoGlyph)?;
parse_char_string(data, self, coordinates, builder)
}
}
impl core::fmt::Debug for Table<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Table {{ ... }}")
}
}

View File

@@ -0,0 +1,238 @@
use super::StringId;
use crate::parser::{FromData, LazyArray16, Stream};
use crate::GlyphId;
/// The Expert Encoding conversion as defined in the Adobe Technical Note #5176 Appendix C.
#[rustfmt::skip]
#[cfg(feature = "glyph-names")]
const EXPERT_ENCODING: &[u16] = &[
0, 1, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 13, 14, 15, 99,
239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 27, 28, 249, 250, 251, 252,
253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 109, 110,
267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282,
283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298,
299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314,
315, 316, 317, 318, 158, 155, 163, 319, 320, 321, 322, 323, 324, 325, 326, 150,
164, 169, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340,
341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356,
357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372,
373, 374, 375, 376, 377, 378,
];
/// The Expert Subset Encoding conversion as defined in the Adobe Technical Note #5176 Appendix C.
#[rustfmt::skip]
#[cfg(feature = "glyph-names")]
const EXPERT_SUBSET_ENCODING: &[u16] = &[
0, 1, 231, 232, 235, 236, 237, 238, 13, 14, 15, 99, 239, 240, 241, 242,
243, 244, 245, 246, 247, 248, 27, 28, 249, 250, 251, 253, 254, 255, 256, 257,
258, 259, 260, 261, 262, 263, 264, 265, 266, 109, 110, 267, 268, 269, 270, 272,
300, 301, 302, 305, 314, 315, 158, 155, 163, 320, 321, 322, 323, 324, 325, 326,
150, 164, 169, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339,
340, 341, 342, 343, 344, 345, 346
];
#[derive(Clone, Copy, Debug)]
pub(crate) struct Format1Range {
first: StringId,
left: u8,
}
impl FromData for Format1Range {
const SIZE: usize = 3;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(Format1Range {
first: s.read::<StringId>()?,
left: s.read::<u8>()?,
})
}
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct Format2Range {
first: StringId,
left: u16,
}
impl FromData for Format2Range {
const SIZE: usize = 4;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(Format2Range {
first: s.read::<StringId>()?,
left: s.read::<u16>()?,
})
}
}
#[derive(Clone, Copy, Debug)]
pub(crate) enum Charset<'a> {
ISOAdobe,
Expert,
ExpertSubset,
Format0(LazyArray16<'a, StringId>),
Format1(LazyArray16<'a, Format1Range>),
Format2(LazyArray16<'a, Format2Range>),
}
impl Charset<'_> {
pub fn sid_to_gid(&self, sid: StringId) -> Option<GlyphId> {
if sid.0 == 0 {
return Some(GlyphId(0));
}
match self {
Charset::ISOAdobe | Charset::Expert | Charset::ExpertSubset => None,
Charset::Format0(ref array) => {
// First glyph is omitted, so we have to add 1.
array
.into_iter()
.position(|n| n == sid)
.map(|n| GlyphId(n as u16 + 1))
}
Charset::Format1(array) => {
let mut glyph_id = GlyphId(1);
for range in *array {
let last = u32::from(range.first.0) + u32::from(range.left);
if range.first <= sid && u32::from(sid.0) <= last {
glyph_id.0 += sid.0 - range.first.0;
return Some(glyph_id);
}
glyph_id.0 += u16::from(range.left) + 1;
}
None
}
Charset::Format2(array) => {
// The same as format 1, but Range::left is u16.
let mut glyph_id = GlyphId(1);
for range in *array {
let last = u32::from(range.first.0) + u32::from(range.left);
if sid >= range.first && u32::from(sid.0) <= last {
glyph_id.0 += sid.0 - range.first.0;
return Some(glyph_id);
}
glyph_id.0 += range.left + 1;
}
None
}
}
}
#[cfg(feature = "glyph-names")]
pub fn gid_to_sid(&self, gid: GlyphId) -> Option<StringId> {
match self {
Charset::ISOAdobe => {
if gid.0 <= 228 {
Some(StringId(gid.0))
} else {
None
}
}
Charset::Expert => EXPERT_ENCODING
.get(usize::from(gid.0))
.cloned()
.map(StringId),
Charset::ExpertSubset => EXPERT_SUBSET_ENCODING
.get(usize::from(gid.0))
.cloned()
.map(StringId),
Charset::Format0(ref array) => {
if gid.0 == 0 {
Some(StringId(0))
} else {
array.get(gid.0 - 1)
}
}
Charset::Format1(array) => {
if gid.0 == 0 {
Some(StringId(0))
} else {
let mut sid = gid.0 - 1;
for range in *array {
if sid <= u16::from(range.left) {
sid = sid.checked_add(range.first.0)?;
return Some(StringId(sid));
}
sid = sid.checked_sub(u16::from(range.left) + 1)?;
}
None
}
}
Charset::Format2(array) => {
if gid.0 == 0 {
Some(StringId(0))
} else {
let mut sid = gid.0 - 1;
for range in *array {
if sid <= range.left {
sid = sid.checked_add(range.first.0)?;
return Some(StringId(sid));
}
sid = sid.checked_sub(range.left.checked_add(1)?)?;
}
None
}
}
}
}
}
pub(crate) fn parse_charset<'a>(number_of_glyphs: u16, s: &mut Stream<'a>) -> Option<Charset<'a>> {
if number_of_glyphs < 2 {
return None;
}
// -1 everywhere, since `.notdef` is omitted.
let format = s.read::<u8>()?;
match format {
0 => Some(Charset::Format0(
s.read_array16::<StringId>(number_of_glyphs - 1)?,
)),
1 => {
// The number of ranges is not defined, so we have to
// read until no glyphs are left.
let mut count = 0;
{
let mut s = s.clone();
let mut total_left = number_of_glyphs - 1;
while total_left > 0 {
s.skip::<StringId>(); // first
let left = s.read::<u8>()?;
total_left = total_left.checked_sub(u16::from(left) + 1)?;
count += 1;
}
}
s.read_array16::<Format1Range>(count).map(Charset::Format1)
}
2 => {
// The same as format 1, but Range::left is u16.
let mut count = 0;
{
let mut s = s.clone();
let mut total_left = number_of_glyphs - 1;
while total_left > 0 {
s.skip::<StringId>(); // first
let left = s.read::<u16>()?.checked_add(1)?;
total_left = total_left.checked_sub(left)?;
count += 1;
}
}
s.read_array16::<Format2Range>(count).map(Charset::Format2)
}
_ => None,
}
}

View File

@@ -0,0 +1,613 @@
use super::argstack::ArgumentsStack;
use super::{f32_abs, Builder, CFFError, IsEven};
use crate::parser::{Fixed, Stream};
pub(crate) struct CharStringParser<'a> {
pub stack: ArgumentsStack<'a>,
pub builder: &'a mut Builder<'a>,
pub x: f32,
pub y: f32,
pub has_move_to: bool,
pub is_first_move_to: bool,
pub width_only: bool, // Exit right after the glyph width is parsed.
}
impl CharStringParser<'_> {
#[inline]
pub fn parse_move_to(&mut self, offset: usize) -> Result<(), CFFError> {
// dx1 dy1
if self.stack.len() != offset + 2 {
return Err(CFFError::InvalidArgumentsStackLength);
}
if self.is_first_move_to {
self.is_first_move_to = false;
} else {
self.builder.close();
}
self.has_move_to = true;
self.x += self.stack.at(offset + 0);
self.y += self.stack.at(offset + 1);
self.builder.move_to(self.x, self.y);
self.stack.clear();
Ok(())
}
#[inline]
pub fn parse_horizontal_move_to(&mut self, offset: usize) -> Result<(), CFFError> {
// dx1
if self.stack.len() != offset + 1 {
return Err(CFFError::InvalidArgumentsStackLength);
}
if self.is_first_move_to {
self.is_first_move_to = false;
} else {
self.builder.close();
}
self.has_move_to = true;
self.x += self.stack.at(offset);
self.builder.move_to(self.x, self.y);
self.stack.clear();
Ok(())
}
#[inline]
pub fn parse_vertical_move_to(&mut self, offset: usize) -> Result<(), CFFError> {
// dy1
if self.stack.len() != offset + 1 {
return Err(CFFError::InvalidArgumentsStackLength);
}
if self.is_first_move_to {
self.is_first_move_to = false;
} else {
self.builder.close();
}
self.has_move_to = true;
self.y += self.stack.at(offset);
self.builder.move_to(self.x, self.y);
self.stack.clear();
Ok(())
}
#[inline]
pub fn parse_line_to(&mut self) -> Result<(), CFFError> {
// {dxa dya}+
if !self.has_move_to {
return Err(CFFError::MissingMoveTo);
}
if self.stack.len().is_odd() {
return Err(CFFError::InvalidArgumentsStackLength);
}
let mut i = 0;
while i < self.stack.len() {
self.x += self.stack.at(i + 0);
self.y += self.stack.at(i + 1);
self.builder.line_to(self.x, self.y);
i += 2;
}
self.stack.clear();
Ok(())
}
#[inline]
pub fn parse_horizontal_line_to(&mut self) -> Result<(), CFFError> {
// dx1 {dya dxb}*
// {dxa dyb}+
if !self.has_move_to {
return Err(CFFError::MissingMoveTo);
}
if self.stack.is_empty() {
return Err(CFFError::InvalidArgumentsStackLength);
}
let mut i = 0;
while i < self.stack.len() {
self.x += self.stack.at(i);
i += 1;
self.builder.line_to(self.x, self.y);
if i == self.stack.len() {
break;
}
self.y += self.stack.at(i);
i += 1;
self.builder.line_to(self.x, self.y);
}
self.stack.clear();
Ok(())
}
#[inline]
pub fn parse_vertical_line_to(&mut self) -> Result<(), CFFError> {
// dy1 {dxa dyb}*
// {dya dxb}+
if !self.has_move_to {
return Err(CFFError::MissingMoveTo);
}
if self.stack.is_empty() {
return Err(CFFError::InvalidArgumentsStackLength);
}
let mut i = 0;
while i < self.stack.len() {
self.y += self.stack.at(i);
i += 1;
self.builder.line_to(self.x, self.y);
if i == self.stack.len() {
break;
}
self.x += self.stack.at(i);
i += 1;
self.builder.line_to(self.x, self.y);
}
self.stack.clear();
Ok(())
}
#[inline]
pub fn parse_curve_to(&mut self) -> Result<(), CFFError> {
// {dxa dya dxb dyb dxc dyc}+
if !self.has_move_to {
return Err(CFFError::MissingMoveTo);
}
if self.stack.len() % 6 != 0 {
return Err(CFFError::InvalidArgumentsStackLength);
}
let mut i = 0;
while i < self.stack.len() {
let x1 = self.x + self.stack.at(i + 0);
let y1 = self.y + self.stack.at(i + 1);
let x2 = x1 + self.stack.at(i + 2);
let y2 = y1 + self.stack.at(i + 3);
self.x = x2 + self.stack.at(i + 4);
self.y = y2 + self.stack.at(i + 5);
self.builder.curve_to(x1, y1, x2, y2, self.x, self.y);
i += 6;
}
self.stack.clear();
Ok(())
}
#[inline]
pub fn parse_curve_line(&mut self) -> Result<(), CFFError> {
// {dxa dya dxb dyb dxc dyc}+ dxd dyd
if !self.has_move_to {
return Err(CFFError::MissingMoveTo);
}
if self.stack.len() < 8 {
return Err(CFFError::InvalidArgumentsStackLength);
}
if (self.stack.len() - 2) % 6 != 0 {
return Err(CFFError::InvalidArgumentsStackLength);
}
let mut i = 0;
while i < self.stack.len() - 2 {
let x1 = self.x + self.stack.at(i + 0);
let y1 = self.y + self.stack.at(i + 1);
let x2 = x1 + self.stack.at(i + 2);
let y2 = y1 + self.stack.at(i + 3);
self.x = x2 + self.stack.at(i + 4);
self.y = y2 + self.stack.at(i + 5);
self.builder.curve_to(x1, y1, x2, y2, self.x, self.y);
i += 6;
}
self.x += self.stack.at(i + 0);
self.y += self.stack.at(i + 1);
self.builder.line_to(self.x, self.y);
self.stack.clear();
Ok(())
}
#[inline]
pub fn parse_line_curve(&mut self) -> Result<(), CFFError> {
// {dxa dya}+ dxb dyb dxc dyc dxd dyd
if !self.has_move_to {
return Err(CFFError::MissingMoveTo);
}
if self.stack.len() < 8 {
return Err(CFFError::InvalidArgumentsStackLength);
}
if (self.stack.len() - 6).is_odd() {
return Err(CFFError::InvalidArgumentsStackLength);
}
let mut i = 0;
while i < self.stack.len() - 6 {
self.x += self.stack.at(i + 0);
self.y += self.stack.at(i + 1);
self.builder.line_to(self.x, self.y);
i += 2;
}
let x1 = self.x + self.stack.at(i + 0);
let y1 = self.y + self.stack.at(i + 1);
let x2 = x1 + self.stack.at(i + 2);
let y2 = y1 + self.stack.at(i + 3);
self.x = x2 + self.stack.at(i + 4);
self.y = y2 + self.stack.at(i + 5);
self.builder.curve_to(x1, y1, x2, y2, self.x, self.y);
self.stack.clear();
Ok(())
}
#[inline]
pub fn parse_hh_curve_to(&mut self) -> Result<(), CFFError> {
// dy1? {dxa dxb dyb dxc}+
if !self.has_move_to {
return Err(CFFError::MissingMoveTo);
}
let mut i = 0;
// The odd argument count indicates an Y position.
if self.stack.len().is_odd() {
self.y += self.stack.at(0);
i += 1;
}
if (self.stack.len() - i) % 4 != 0 {
return Err(CFFError::InvalidArgumentsStackLength);
}
while i < self.stack.len() {
let x1 = self.x + self.stack.at(i + 0);
let y1 = self.y;
let x2 = x1 + self.stack.at(i + 1);
let y2 = y1 + self.stack.at(i + 2);
self.x = x2 + self.stack.at(i + 3);
self.y = y2;
self.builder.curve_to(x1, y1, x2, y2, self.x, self.y);
i += 4;
}
self.stack.clear();
Ok(())
}
#[inline]
pub fn parse_vv_curve_to(&mut self) -> Result<(), CFFError> {
// dx1? {dya dxb dyb dyc}+
if !self.has_move_to {
return Err(CFFError::MissingMoveTo);
}
let mut i = 0;
// The odd argument count indicates an X position.
if self.stack.len().is_odd() {
self.x += self.stack.at(0);
i += 1;
}
if (self.stack.len() - i) % 4 != 0 {
return Err(CFFError::InvalidArgumentsStackLength);
}
while i < self.stack.len() {
let x1 = self.x;
let y1 = self.y + self.stack.at(i + 0);
let x2 = x1 + self.stack.at(i + 1);
let y2 = y1 + self.stack.at(i + 2);
self.x = x2;
self.y = y2 + self.stack.at(i + 3);
self.builder.curve_to(x1, y1, x2, y2, self.x, self.y);
i += 4;
}
self.stack.clear();
Ok(())
}
#[inline]
pub fn parse_hv_curve_to(&mut self) -> Result<(), CFFError> {
// dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}* dxf?
// {dxa dxb dyb dyc dyd dxe dye dxf}+ dyf?
if !self.has_move_to {
return Err(CFFError::MissingMoveTo);
}
if self.stack.len() < 4 {
return Err(CFFError::InvalidArgumentsStackLength);
}
self.stack.reverse();
while !self.stack.is_empty() {
if self.stack.len() < 4 {
return Err(CFFError::InvalidArgumentsStackLength);
}
let x1 = self.x + self.stack.pop();
let y1 = self.y;
let x2 = x1 + self.stack.pop();
let y2 = y1 + self.stack.pop();
self.y = y2 + self.stack.pop();
self.x = x2;
if self.stack.len() == 1 {
self.x += self.stack.pop();
}
self.builder.curve_to(x1, y1, x2, y2, self.x, self.y);
if self.stack.is_empty() {
break;
}
if self.stack.len() < 4 {
return Err(CFFError::InvalidArgumentsStackLength);
}
let x1 = self.x;
let y1 = self.y + self.stack.pop();
let x2 = x1 + self.stack.pop();
let y2 = y1 + self.stack.pop();
self.x = x2 + self.stack.pop();
self.y = y2;
if self.stack.len() == 1 {
self.y += self.stack.pop()
}
self.builder.curve_to(x1, y1, x2, y2, self.x, self.y);
}
debug_assert!(self.stack.is_empty());
Ok(())
}
#[inline]
pub fn parse_vh_curve_to(&mut self) -> Result<(), CFFError> {
// dy1 dx2 dy2 dx3 {dxa dxb dyb dyc dyd dxe dye dxf}* dyf?
// {dya dxb dyb dxc dxd dxe dye dyf}+ dxf?
if !self.has_move_to {
return Err(CFFError::MissingMoveTo);
}
if self.stack.len() < 4 {
return Err(CFFError::InvalidArgumentsStackLength);
}
self.stack.reverse();
while !self.stack.is_empty() {
if self.stack.len() < 4 {
return Err(CFFError::InvalidArgumentsStackLength);
}
let x1 = self.x;
let y1 = self.y + self.stack.pop();
let x2 = x1 + self.stack.pop();
let y2 = y1 + self.stack.pop();
self.x = x2 + self.stack.pop();
self.y = y2;
if self.stack.len() == 1 {
self.y += self.stack.pop();
}
self.builder.curve_to(x1, y1, x2, y2, self.x, self.y);
if self.stack.is_empty() {
break;
}
if self.stack.len() < 4 {
return Err(CFFError::InvalidArgumentsStackLength);
}
let x1 = self.x + self.stack.pop();
let y1 = self.y;
let x2 = x1 + self.stack.pop();
let y2 = y1 + self.stack.pop();
self.y = y2 + self.stack.pop();
self.x = x2;
if self.stack.len() == 1 {
self.x += self.stack.pop();
}
self.builder.curve_to(x1, y1, x2, y2, self.x, self.y);
}
debug_assert!(self.stack.is_empty());
Ok(())
}
#[inline]
pub fn parse_flex(&mut self) -> Result<(), CFFError> {
// dx1 dy1 dx2 dy2 dx3 dy3 dx4 dy4 dx5 dy5 dx6 dy6 fd
if !self.has_move_to {
return Err(CFFError::MissingMoveTo);
}
if self.stack.len() != 13 {
return Err(CFFError::InvalidArgumentsStackLength);
}
let dx1 = self.x + self.stack.at(0);
let dy1 = self.y + self.stack.at(1);
let dx2 = dx1 + self.stack.at(2);
let dy2 = dy1 + self.stack.at(3);
let dx3 = dx2 + self.stack.at(4);
let dy3 = dy2 + self.stack.at(5);
let dx4 = dx3 + self.stack.at(6);
let dy4 = dy3 + self.stack.at(7);
let dx5 = dx4 + self.stack.at(8);
let dy5 = dy4 + self.stack.at(9);
self.x = dx5 + self.stack.at(10);
self.y = dy5 + self.stack.at(11);
self.builder.curve_to(dx1, dy1, dx2, dy2, dx3, dy3);
self.builder.curve_to(dx4, dy4, dx5, dy5, self.x, self.y);
self.stack.clear();
Ok(())
}
#[inline]
pub fn parse_flex1(&mut self) -> Result<(), CFFError> {
// dx1 dy1 dx2 dy2 dx3 dy3 dx4 dy4 dx5 dy5 d6
if !self.has_move_to {
return Err(CFFError::MissingMoveTo);
}
if self.stack.len() != 11 {
return Err(CFFError::InvalidArgumentsStackLength);
}
let dx1 = self.x + self.stack.at(0);
let dy1 = self.y + self.stack.at(1);
let dx2 = dx1 + self.stack.at(2);
let dy2 = dy1 + self.stack.at(3);
let dx3 = dx2 + self.stack.at(4);
let dy3 = dy2 + self.stack.at(5);
let dx4 = dx3 + self.stack.at(6);
let dy4 = dy3 + self.stack.at(7);
let dx5 = dx4 + self.stack.at(8);
let dy5 = dy4 + self.stack.at(9);
if f32_abs(dx5 - self.x) > f32_abs(dy5 - self.y) {
self.x = dx5 + self.stack.at(10);
} else {
self.y = dy5 + self.stack.at(10);
}
self.builder.curve_to(dx1, dy1, dx2, dy2, dx3, dy3);
self.builder.curve_to(dx4, dy4, dx5, dy5, self.x, self.y);
self.stack.clear();
Ok(())
}
#[inline]
pub fn parse_hflex(&mut self) -> Result<(), CFFError> {
// dx1 dx2 dy2 dx3 dx4 dx5 dx6
if !self.has_move_to {
return Err(CFFError::MissingMoveTo);
}
if self.stack.len() != 7 {
return Err(CFFError::InvalidArgumentsStackLength);
}
let dx1 = self.x + self.stack.at(0);
let dy1 = self.y;
let dx2 = dx1 + self.stack.at(1);
let dy2 = dy1 + self.stack.at(2);
let dx3 = dx2 + self.stack.at(3);
let dy3 = dy2;
let dx4 = dx3 + self.stack.at(4);
let dy4 = dy2;
let dx5 = dx4 + self.stack.at(5);
let dy5 = self.y;
self.x = dx5 + self.stack.at(6);
self.builder.curve_to(dx1, dy1, dx2, dy2, dx3, dy3);
self.builder.curve_to(dx4, dy4, dx5, dy5, self.x, self.y);
self.stack.clear();
Ok(())
}
#[inline]
pub fn parse_hflex1(&mut self) -> Result<(), CFFError> {
// dx1 dy1 dx2 dy2 dx3 dx4 dx5 dy5 dx6
if !self.has_move_to {
return Err(CFFError::MissingMoveTo);
}
if self.stack.len() != 9 {
return Err(CFFError::InvalidArgumentsStackLength);
}
let dx1 = self.x + self.stack.at(0);
let dy1 = self.y + self.stack.at(1);
let dx2 = dx1 + self.stack.at(2);
let dy2 = dy1 + self.stack.at(3);
let dx3 = dx2 + self.stack.at(4);
let dy3 = dy2;
let dx4 = dx3 + self.stack.at(5);
let dy4 = dy2;
let dx5 = dx4 + self.stack.at(6);
let dy5 = dy4 + self.stack.at(7);
self.x = dx5 + self.stack.at(8);
self.builder.curve_to(dx1, dy1, dx2, dy2, dx3, dy3);
self.builder.curve_to(dx4, dy4, dx5, dy5, self.x, self.y);
self.stack.clear();
Ok(())
}
#[inline]
pub fn parse_int1(&mut self, op: u8) -> Result<(), CFFError> {
let n = i16::from(op) - 139;
self.stack.push(f32::from(n))?;
Ok(())
}
#[inline]
pub fn parse_int2(&mut self, op: u8, s: &mut Stream) -> Result<(), CFFError> {
let b1 = s.read::<u8>().ok_or(CFFError::ReadOutOfBounds)?;
let n = (i16::from(op) - 247) * 256 + i16::from(b1) + 108;
debug_assert!((108..=1131).contains(&n));
self.stack.push(f32::from(n))?;
Ok(())
}
#[inline]
pub fn parse_int3(&mut self, op: u8, s: &mut Stream) -> Result<(), CFFError> {
let b1 = s.read::<u8>().ok_or(CFFError::ReadOutOfBounds)?;
let n = -(i16::from(op) - 251) * 256 - i16::from(b1) - 108;
debug_assert!((-1131..=-108).contains(&n));
self.stack.push(f32::from(n))?;
Ok(())
}
#[inline]
pub fn parse_fixed(&mut self, s: &mut Stream) -> Result<(), CFFError> {
let n = s.read::<Fixed>().ok_or(CFFError::ReadOutOfBounds)?;
self.stack.push(n.0)?;
Ok(())
}
}

310
vendor/ttf-parser/src/tables/cff/dict.rs vendored Normal file
View File

@@ -0,0 +1,310 @@
use core::convert::TryFrom;
use core::ops::Range;
use crate::Stream;
// Limits according to the Adobe Technical Note #5176, chapter 4 DICT Data.
const TWO_BYTE_OPERATOR_MARK: u8 = 12;
const FLOAT_STACK_LEN: usize = 64;
const END_OF_FLOAT_FLAG: u8 = 0xf;
#[derive(Clone, Copy, Debug)]
pub struct Operator(pub u16);
impl Operator {
#[inline]
pub fn get(self) -> u16 {
self.0
}
}
pub struct DictionaryParser<'a> {
data: &'a [u8],
// The current offset.
offset: usize,
// Offset to the last operands start.
operands_offset: usize,
// Actual operands.
//
// While CFF can contain only i32 and f32 values, we have to store operands as f64
// since f32 cannot represent the whole i32 range.
// Meaning we have a choice of storing operands as f64 or as enum of i32/f32.
// In both cases the type size would be 8 bytes, so it's easier to simply use f64.
operands: &'a mut [f64],
// An amount of operands in the `operands` array.
operands_len: u16,
}
impl<'a> DictionaryParser<'a> {
#[inline]
pub fn new(data: &'a [u8], operands_buffer: &'a mut [f64]) -> Self {
DictionaryParser {
data,
offset: 0,
operands_offset: 0,
operands: operands_buffer,
operands_len: 0,
}
}
#[inline(never)]
pub fn parse_next(&mut self) -> Option<Operator> {
let mut s = Stream::new_at(self.data, self.offset)?;
self.operands_offset = self.offset;
while !s.at_end() {
let b = s.read::<u8>()?;
// 0..=21 bytes are operators.
if is_dict_one_byte_op(b) {
let mut operator = u16::from(b);
// Check that operator is two byte long.
if b == TWO_BYTE_OPERATOR_MARK {
// Use a 1200 'prefix' to make two byte operators more readable.
// 12 3 => 1203
operator = 1200 + u16::from(s.read::<u8>()?);
}
self.offset = s.offset();
return Some(Operator(operator));
} else {
skip_number(b, &mut s)?;
}
}
None
}
/// Parses operands of the current operator.
///
/// In the DICT structure, operands are defined before an operator.
/// So we are trying to find an operator first and the we can actually parse the operands.
///
/// Since this methods is pretty expensive and we do not care about most of the operators,
/// we can speed up parsing by parsing operands only for required operators.
///
/// We still have to "skip" operands during operators search (see `skip_number()`),
/// but it's still faster that a naive method.
pub fn parse_operands(&mut self) -> Option<()> {
let mut s = Stream::new_at(self.data, self.operands_offset)?;
self.operands_len = 0;
while !s.at_end() {
let b = s.read::<u8>()?;
// 0..=21 bytes are operators.
if is_dict_one_byte_op(b) {
break;
} else {
let op = parse_number(b, &mut s)?;
self.operands[usize::from(self.operands_len)] = op;
self.operands_len += 1;
if usize::from(self.operands_len) >= self.operands.len() {
break;
}
}
}
Some(())
}
#[inline]
pub fn operands(&self) -> &[f64] {
&self.operands[..usize::from(self.operands_len)]
}
#[inline]
pub fn parse_number(&mut self) -> Option<f64> {
self.parse_operands()?;
self.operands().get(0).cloned()
}
#[inline]
pub fn parse_offset(&mut self) -> Option<usize> {
self.parse_operands()?;
let operands = self.operands();
if operands.len() == 1 {
usize::try_from(operands[0] as i32).ok()
} else {
None
}
}
#[inline]
pub fn parse_range(&mut self) -> Option<Range<usize>> {
self.parse_operands()?;
let operands = self.operands();
if operands.len() == 2 {
let len = usize::try_from(operands[0] as i32).ok()?;
let start = usize::try_from(operands[1] as i32).ok()?;
let end = start.checked_add(len)?;
Some(start..end)
} else {
None
}
}
}
// One-byte CFF DICT Operators according to the
// Adobe Technical Note #5176, Appendix H CFF DICT Encoding.
pub fn is_dict_one_byte_op(b: u8) -> bool {
match b {
0..=27 => true,
28..=30 => false, // numbers
31 => true, // Reserved
32..=254 => false, // numbers
255 => true, // Reserved
}
}
// Adobe Technical Note #5177, Table 3 Operand Encoding
pub fn parse_number(b0: u8, s: &mut Stream) -> Option<f64> {
match b0 {
28 => {
let n = i32::from(s.read::<i16>()?);
Some(f64::from(n))
}
29 => {
let n = s.read::<i32>()?;
Some(f64::from(n))
}
30 => parse_float(s),
32..=246 => {
let n = i32::from(b0) - 139;
Some(f64::from(n))
}
247..=250 => {
let b1 = i32::from(s.read::<u8>()?);
let n = (i32::from(b0) - 247) * 256 + b1 + 108;
Some(f64::from(n))
}
251..=254 => {
let b1 = i32::from(s.read::<u8>()?);
let n = -(i32::from(b0) - 251) * 256 - b1 - 108;
Some(f64::from(n))
}
_ => None,
}
}
fn parse_float(s: &mut Stream) -> Option<f64> {
let mut data = [0u8; FLOAT_STACK_LEN];
let mut idx = 0;
loop {
let b1: u8 = s.read()?;
let nibble1 = b1 >> 4;
let nibble2 = b1 & 15;
if nibble1 == END_OF_FLOAT_FLAG {
break;
}
idx = parse_float_nibble(nibble1, idx, &mut data)?;
if nibble2 == END_OF_FLOAT_FLAG {
break;
}
idx = parse_float_nibble(nibble2, idx, &mut data)?;
}
let s = core::str::from_utf8(&data[..idx]).ok()?;
let n = s.parse().ok()?;
Some(n)
}
// Adobe Technical Note #5176, Table 5 Nibble Definitions
fn parse_float_nibble(nibble: u8, mut idx: usize, data: &mut [u8]) -> Option<usize> {
if idx == FLOAT_STACK_LEN {
return None;
}
match nibble {
0..=9 => {
data[idx] = b'0' + nibble;
}
10 => {
data[idx] = b'.';
}
11 => {
data[idx] = b'E';
}
12 => {
if idx + 1 == FLOAT_STACK_LEN {
return None;
}
data[idx] = b'E';
idx += 1;
data[idx] = b'-';
}
13 => {
return None;
}
14 => {
data[idx] = b'-';
}
_ => {
return None;
}
}
idx += 1;
Some(idx)
}
// Just like `parse_number`, but doesn't actually parses the data.
pub fn skip_number(b0: u8, s: &mut Stream) -> Option<()> {
match b0 {
28 => s.skip::<u16>(),
29 => s.skip::<u32>(),
30 => {
while !s.at_end() {
let b1 = s.read::<u8>()?;
let nibble1 = b1 >> 4;
let nibble2 = b1 & 15;
if nibble1 == END_OF_FLOAT_FLAG || nibble2 == END_OF_FLOAT_FLAG {
break;
}
}
}
32..=246 => {}
247..=250 => s.skip::<u8>(),
251..=254 => s.skip::<u8>(),
_ => return None,
}
Some(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_dict_number() {
assert_eq!(
parse_number(0xFA, &mut Stream::new(&[0x7C])).unwrap(),
1000.0
);
assert_eq!(
parse_number(0xFE, &mut Stream::new(&[0x7C])).unwrap(),
-1000.0
);
assert_eq!(
parse_number(0x1C, &mut Stream::new(&[0x27, 0x10])).unwrap(),
10000.0
);
assert_eq!(
parse_number(0x1C, &mut Stream::new(&[0xD8, 0xF0])).unwrap(),
-10000.0
);
assert_eq!(
parse_number(0x1D, &mut Stream::new(&[0x00, 0x01, 0x86, 0xA0])).unwrap(),
100000.0
);
assert_eq!(
parse_number(0x1D, &mut Stream::new(&[0xFF, 0xFE, 0x79, 0x60])).unwrap(),
-100000.0
);
}
}

View File

@@ -0,0 +1,173 @@
use super::charset::Charset;
use super::StringId;
use crate::parser::{FromData, LazyArray16, Stream};
use crate::GlyphId;
/// The Standard Encoding as defined in the Adobe Technical Note #5176 Appendix B.
#[rustfmt::skip]
pub const STANDARD_ENCODING: [u8; 256] = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
0, 111, 112, 113, 114, 0, 115, 116, 117, 118, 119, 120, 121, 122, 0, 123,
0, 124, 125, 126, 127, 128, 129, 130, 131, 0, 132, 133, 0, 134, 135, 136,
137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 138, 0, 139, 0, 0, 0, 0, 140, 141, 142, 143, 0, 0, 0, 0,
0, 144, 0, 0, 0, 145, 0, 0, 146, 147, 148, 149, 0, 0, 0, 0,
];
#[derive(Clone, Copy, Debug)]
pub(crate) struct Format1Range {
first: u8,
left: u8,
}
impl FromData for Format1Range {
const SIZE: usize = 2;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(Format1Range {
first: s.read::<u8>()?,
left: s.read::<u8>()?,
})
}
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct Supplement {
code: u8,
name: StringId,
}
impl FromData for Supplement {
const SIZE: usize = 3;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(Supplement {
code: s.read::<u8>()?,
name: s.read::<StringId>()?,
})
}
}
#[derive(Clone, Copy, Default, Debug)]
pub(crate) struct Encoding<'a> {
kind: EncodingKind<'a>,
supplemental: LazyArray16<'a, Supplement>,
}
#[derive(Clone, Copy, Debug)]
pub(crate) enum EncodingKind<'a> {
Standard,
Expert,
Format0(LazyArray16<'a, u8>),
Format1(LazyArray16<'a, Format1Range>),
}
impl Default for EncodingKind<'_> {
fn default() -> Self {
Self::Standard
}
}
impl Encoding<'_> {
pub fn new_standard() -> Self {
Encoding {
kind: EncodingKind::Standard,
supplemental: LazyArray16::default(),
}
}
pub fn new_expert() -> Self {
Encoding {
kind: EncodingKind::Expert,
supplemental: LazyArray16::default(),
}
}
pub fn code_to_gid(&self, charset: &Charset, code: u8) -> Option<GlyphId> {
if !self.supplemental.is_empty() {
if let Some(ref s) = self.supplemental.into_iter().find(|s| s.code == code) {
return charset.sid_to_gid(s.name);
}
}
let index = usize::from(code);
match self.kind {
// Standard encodings store a StringID/SID and not GlyphID/GID.
// Therefore we have to get SID first and then convert it to GID via Charset.
// Custom encodings (FormatN) store GID directly.
//
// Indexing for predefined encodings never fails,
// because `code` is always `u8` and encodings have 256 entries.
//
// We treat `Expert` as `Standard` as well, since we allow only 8bit codepoints.
EncodingKind::Standard | EncodingKind::Expert => {
let sid = StringId(u16::from(STANDARD_ENCODING[index]));
charset.sid_to_gid(sid)
}
EncodingKind::Format0(ref table) => {
// +1 because .notdef is implicit.
table
.into_iter()
.position(|c| c == code)
.map(|i| (i + 1) as u16)
.map(GlyphId)
}
EncodingKind::Format1(ref table) => {
// Starts from 1 because .notdef is implicit.
let mut gid: u16 = 1;
for range in table.into_iter() {
let end = range.first.saturating_add(range.left);
if (range.first..=end).contains(&code) {
gid += u16::from(code - range.first);
return Some(GlyphId(gid));
} else {
gid += u16::from(range.left) + 1;
}
}
None
}
}
}
}
pub(crate) fn parse_encoding<'a>(s: &mut Stream<'a>) -> Option<Encoding<'a>> {
let format = s.read::<u8>()?;
// The first high-bit in format indicates that a Supplemental encoding is present.
// Check it and clear.
let has_supplemental = format & 0x80 != 0;
let format = format & 0x7f;
let count = u16::from(s.read::<u8>()?);
let kind = match format {
// TODO: read_array8?
0 => s.read_array16::<u8>(count).map(EncodingKind::Format0)?,
1 => s
.read_array16::<Format1Range>(count)
.map(EncodingKind::Format1)?,
_ => return None,
};
let supplemental = if has_supplemental {
let count = u16::from(s.read::<u8>()?);
s.read_array16::<Supplement>(count)?
} else {
LazyArray16::default()
};
Some(Encoding { kind, supplemental })
}

View File

@@ -0,0 +1,236 @@
use crate::parser::{FromData, NumFrom, Stream, U24};
pub trait IndexSize: FromData {
fn to_u32(self) -> u32;
}
impl IndexSize for u16 {
fn to_u32(self) -> u32 {
u32::from(self)
}
}
impl IndexSize for u32 {
fn to_u32(self) -> u32 {
self
}
}
#[inline]
pub fn parse_index<'a, T: IndexSize>(s: &mut Stream<'a>) -> Option<Index<'a>> {
let count = s.read::<T>()?;
parse_index_impl(count.to_u32(), s)
}
#[inline(never)]
fn parse_index_impl<'a>(count: u32, s: &mut Stream<'a>) -> Option<Index<'a>> {
if count == 0 || count == core::u32::MAX {
return Some(Index::default());
}
let offset_size = s.read::<OffsetSize>()?;
let offsets_len = (count + 1).checked_mul(offset_size.to_u32())?;
let offsets = VarOffsets {
data: s.read_bytes(usize::num_from(offsets_len))?,
offset_size,
};
// Last offset indicates a Data Index size.
match offsets.last() {
Some(last_offset) => {
let data = s.read_bytes(usize::num_from(last_offset))?;
Some(Index { data, offsets })
}
None => Some(Index::default()),
}
}
#[inline]
pub fn skip_index<T: IndexSize>(s: &mut Stream) -> Option<()> {
let count = s.read::<T>()?;
skip_index_impl(count.to_u32(), s)
}
#[inline(never)]
fn skip_index_impl(count: u32, s: &mut Stream) -> Option<()> {
if count == 0 || count == core::u32::MAX {
return Some(());
}
let offset_size = s.read::<OffsetSize>()?;
let offsets_len = (count + 1).checked_mul(offset_size.to_u32())?;
let offsets = VarOffsets {
data: s.read_bytes(usize::num_from(offsets_len))?,
offset_size,
};
if let Some(last_offset) = offsets.last() {
s.advance(usize::num_from(last_offset));
}
Some(())
}
#[derive(Clone, Copy, Debug)]
pub struct VarOffsets<'a> {
pub data: &'a [u8],
pub offset_size: OffsetSize,
}
impl<'a> VarOffsets<'a> {
pub fn get(&self, index: u32) -> Option<u32> {
if index >= self.len() {
return None;
}
let start = usize::num_from(index) * self.offset_size.to_usize();
let mut s = Stream::new_at(self.data, start)?;
let n: u32 = match self.offset_size {
OffsetSize::Size1 => u32::from(s.read::<u8>()?),
OffsetSize::Size2 => u32::from(s.read::<u16>()?),
OffsetSize::Size3 => s.read::<U24>()?.0,
OffsetSize::Size4 => s.read::<u32>()?,
};
// Offsets are offset by one byte in the font,
// so we have to shift them back.
n.checked_sub(1)
}
#[inline]
pub fn last(&self) -> Option<u32> {
if !self.is_empty() {
self.get(self.len() - 1)
} else {
None
}
}
#[inline]
pub fn len(&self) -> u32 {
self.data.len() as u32 / self.offset_size as u32
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
#[derive(Clone, Copy, Debug)]
pub struct Index<'a> {
pub data: &'a [u8],
pub offsets: VarOffsets<'a>,
}
impl<'a> Default for Index<'a> {
#[inline]
fn default() -> Self {
Index {
data: b"",
offsets: VarOffsets {
data: b"",
offset_size: OffsetSize::Size1,
},
}
}
}
impl<'a> IntoIterator for Index<'a> {
type Item = &'a [u8];
type IntoIter = IndexIter<'a>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
IndexIter {
data: self,
offset_index: 0,
}
}
}
impl<'a> Index<'a> {
#[inline]
pub fn len(&self) -> u32 {
// Last offset points to the byte after the `Object data`. We should skip it.
self.offsets.len().saturating_sub(1)
}
pub fn get(&self, index: u32) -> Option<&'a [u8]> {
let next_index = index.checked_add(1)?; // make sure we do not overflow
let start = usize::num_from(self.offsets.get(index)?);
let end = usize::num_from(self.offsets.get(next_index)?);
self.data.get(start..end)
}
}
pub struct IndexIter<'a> {
data: Index<'a>,
offset_index: u32,
}
impl<'a> Iterator for IndexIter<'a> {
type Item = &'a [u8];
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.offset_index == self.data.len() {
return None;
}
let index = self.offset_index;
self.offset_index += 1;
self.data.get(index)
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum OffsetSize {
Size1 = 1,
Size2 = 2,
Size3 = 3,
Size4 = 4,
}
impl OffsetSize {
#[inline]
pub fn to_u32(self) -> u32 {
self as u32
}
#[inline]
pub fn to_usize(self) -> usize {
self as usize
}
}
impl FromData for OffsetSize {
const SIZE: usize = 1;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
match data.get(0)? {
1 => Some(OffsetSize::Size1),
2 => Some(OffsetSize::Size2),
3 => Some(OffsetSize::Size3),
4 => Some(OffsetSize::Size4),
_ => None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_offset_size() {
assert_eq!(core::mem::size_of::<OffsetSize>(), 1);
assert_eq!(Stream::new(&[0x00]).read::<OffsetSize>(), None);
assert_eq!(
Stream::new(&[0x01]).read::<OffsetSize>(),
Some(OffsetSize::Size1)
);
assert_eq!(Stream::new(&[0x05]).read::<OffsetSize>(), None);
}
}

147
vendor/ttf-parser/src/tables/cff/mod.rs vendored Normal file
View File

@@ -0,0 +1,147 @@
mod argstack;
pub mod cff1;
#[cfg(feature = "variable-fonts")]
pub mod cff2;
mod charset;
mod charstring;
mod dict;
mod encoding;
mod index;
#[cfg(feature = "glyph-names")]
mod std_names;
use core::convert::TryFrom;
use crate::parser::{FromData, TryNumFrom};
use crate::{OutlineBuilder, RectF};
/// A list of errors that can occur during a CFF glyph outlining.
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum CFFError {
NoGlyph,
ReadOutOfBounds,
ZeroBBox,
InvalidOperator,
UnsupportedOperator,
MissingEndChar,
DataAfterEndChar,
NestingLimitReached,
ArgumentsStackLimitReached,
InvalidArgumentsStackLength,
BboxOverflow,
MissingMoveTo,
InvalidSubroutineIndex,
NoLocalSubroutines,
InvalidSeacCode,
#[cfg(feature = "variable-fonts")]
InvalidItemVariationDataIndex,
#[cfg(feature = "variable-fonts")]
InvalidNumberOfBlendOperands,
#[cfg(feature = "variable-fonts")]
BlendRegionsLimitReached,
}
pub(crate) struct Builder<'a> {
builder: &'a mut dyn OutlineBuilder,
bbox: RectF,
}
impl<'a> Builder<'a> {
#[inline]
fn move_to(&mut self, x: f32, y: f32) {
self.bbox.extend_by(x, y);
self.builder.move_to(x, y);
}
#[inline]
fn line_to(&mut self, x: f32, y: f32) {
self.bbox.extend_by(x, y);
self.builder.line_to(x, y);
}
#[inline]
fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x: f32, y: f32) {
self.bbox.extend_by(x1, y1);
self.bbox.extend_by(x2, y2);
self.bbox.extend_by(x, y);
self.builder.curve_to(x1, y1, x2, y2, x, y);
}
#[inline]
fn close(&mut self) {
self.builder.close();
}
}
/// A type-safe wrapper for string ID.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Debug)]
pub struct StringId(u16);
impl FromData for StringId {
const SIZE: usize = 2;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
u16::parse(data).map(StringId)
}
}
pub trait IsEven {
fn is_even(&self) -> bool;
fn is_odd(&self) -> bool;
}
impl IsEven for usize {
#[inline]
fn is_even(&self) -> bool {
(*self) & 1 == 0
}
#[inline]
fn is_odd(&self) -> bool {
!self.is_even()
}
}
#[cfg(feature = "std")]
#[inline]
pub fn f32_abs(n: f32) -> f32 {
n.abs()
}
#[cfg(not(feature = "std"))]
#[inline]
pub fn f32_abs(n: f32) -> f32 {
if n.is_sign_negative() {
-n
} else {
n
}
}
#[inline]
pub fn conv_subroutine_index(index: f32, bias: u16) -> Result<u32, CFFError> {
conv_subroutine_index_impl(index, bias).ok_or(CFFError::InvalidSubroutineIndex)
}
#[inline]
fn conv_subroutine_index_impl(index: f32, bias: u16) -> Option<u32> {
let index = i32::try_num_from(index)?;
let bias = i32::from(bias);
let index = index.checked_add(bias)?;
u32::try_from(index).ok()
}
// Adobe Technical Note #5176, Chapter 16 "Local / Global Subrs INDEXes"
#[inline]
pub fn calc_subroutine_bias(len: u32) -> u16 {
if len < 1240 {
107
} else if len < 33900 {
1131
} else {
32768
}
}

View File

@@ -0,0 +1,393 @@
pub const STANDARD_NAMES: &[&str] = &[
".notdef",
"space",
"exclam",
"quotedbl",
"numbersign",
"dollar",
"percent",
"ampersand",
"quoteright",
"parenleft",
"parenright",
"asterisk",
"plus",
"comma",
"hyphen",
"period",
"slash",
"zero",
"one",
"two",
"three",
"four",
"five",
"six",
"seven",
"eight",
"nine",
"colon",
"semicolon",
"less",
"equal",
"greater",
"question",
"at",
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"I",
"J",
"K",
"L",
"M",
"N",
"O",
"P",
"Q",
"R",
"S",
"T",
"U",
"V",
"W",
"X",
"Y",
"Z",
"bracketleft",
"backslash",
"bracketright",
"asciicircum",
"underscore",
"quoteleft",
"a",
"b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
"m",
"n",
"o",
"p",
"q",
"r",
"s",
"t",
"u",
"v",
"w",
"x",
"y",
"z",
"braceleft",
"bar",
"braceright",
"asciitilde",
"exclamdown",
"cent",
"sterling",
"fraction",
"yen",
"florin",
"section",
"currency",
"quotesingle",
"quotedblleft",
"guillemotleft",
"guilsinglleft",
"guilsinglright",
"fi",
"fl",
"endash",
"dagger",
"daggerdbl",
"periodcentered",
"paragraph",
"bullet",
"quotesinglbase",
"quotedblbase",
"quotedblright",
"guillemotright",
"ellipsis",
"perthousand",
"questiondown",
"grave",
"acute",
"circumflex",
"tilde",
"macron",
"breve",
"dotaccent",
"dieresis",
"ring",
"cedilla",
"hungarumlaut",
"ogonek",
"caron",
"emdash",
"AE",
"ordfeminine",
"Lslash",
"Oslash",
"OE",
"ordmasculine",
"ae",
"dotlessi",
"lslash",
"oslash",
"oe",
"germandbls",
"onesuperior",
"logicalnot",
"mu",
"trademark",
"Eth",
"onehalf",
"plusminus",
"Thorn",
"onequarter",
"divide",
"brokenbar",
"degree",
"thorn",
"threequarters",
"twosuperior",
"registered",
"minus",
"eth",
"multiply",
"threesuperior",
"copyright",
"Aacute",
"Acircumflex",
"Adieresis",
"Agrave",
"Aring",
"Atilde",
"Ccedilla",
"Eacute",
"Ecircumflex",
"Edieresis",
"Egrave",
"Iacute",
"Icircumflex",
"Idieresis",
"Igrave",
"Ntilde",
"Oacute",
"Ocircumflex",
"Odieresis",
"Ograve",
"Otilde",
"Scaron",
"Uacute",
"Ucircumflex",
"Udieresis",
"Ugrave",
"Yacute",
"Ydieresis",
"Zcaron",
"aacute",
"acircumflex",
"adieresis",
"agrave",
"aring",
"atilde",
"ccedilla",
"eacute",
"ecircumflex",
"edieresis",
"egrave",
"iacute",
"icircumflex",
"idieresis",
"igrave",
"ntilde",
"oacute",
"ocircumflex",
"odieresis",
"ograve",
"otilde",
"scaron",
"uacute",
"ucircumflex",
"udieresis",
"ugrave",
"yacute",
"ydieresis",
"zcaron",
"exclamsmall",
"Hungarumlautsmall",
"dollaroldstyle",
"dollarsuperior",
"ampersandsmall",
"Acutesmall",
"parenleftsuperior",
"parenrightsuperior",
"twodotenleader",
"onedotenleader",
"zerooldstyle",
"oneoldstyle",
"twooldstyle",
"threeoldstyle",
"fouroldstyle",
"fiveoldstyle",
"sixoldstyle",
"sevenoldstyle",
"eightoldstyle",
"nineoldstyle",
"commasuperior",
"threequartersemdash",
"periodsuperior",
"questionsmall",
"asuperior",
"bsuperior",
"centsuperior",
"dsuperior",
"esuperior",
"isuperior",
"lsuperior",
"msuperior",
"nsuperior",
"osuperior",
"rsuperior",
"ssuperior",
"tsuperior",
"ff",
"ffi",
"ffl",
"parenleftinferior",
"parenrightinferior",
"Circumflexsmall",
"hyphensuperior",
"Gravesmall",
"Asmall",
"Bsmall",
"Csmall",
"Dsmall",
"Esmall",
"Fsmall",
"Gsmall",
"Hsmall",
"Ismall",
"Jsmall",
"Ksmall",
"Lsmall",
"Msmall",
"Nsmall",
"Osmall",
"Psmall",
"Qsmall",
"Rsmall",
"Ssmall",
"Tsmall",
"Usmall",
"Vsmall",
"Wsmall",
"Xsmall",
"Ysmall",
"Zsmall",
"colonmonetary",
"onefitted",
"rupiah",
"Tildesmall",
"exclamdownsmall",
"centoldstyle",
"Lslashsmall",
"Scaronsmall",
"Zcaronsmall",
"Dieresissmall",
"Brevesmall",
"Caronsmall",
"Dotaccentsmall",
"Macronsmall",
"figuredash",
"hypheninferior",
"Ogoneksmall",
"Ringsmall",
"Cedillasmall",
"questiondownsmall",
"oneeighth",
"threeeighths",
"fiveeighths",
"seveneighths",
"onethird",
"twothirds",
"zerosuperior",
"foursuperior",
"fivesuperior",
"sixsuperior",
"sevensuperior",
"eightsuperior",
"ninesuperior",
"zeroinferior",
"oneinferior",
"twoinferior",
"threeinferior",
"fourinferior",
"fiveinferior",
"sixinferior",
"seveninferior",
"eightinferior",
"nineinferior",
"centinferior",
"dollarinferior",
"periodinferior",
"commainferior",
"Agravesmall",
"Aacutesmall",
"Acircumflexsmall",
"Atildesmall",
"Adieresissmall",
"Aringsmall",
"AEsmall",
"Ccedillasmall",
"Egravesmall",
"Eacutesmall",
"Ecircumflexsmall",
"Edieresissmall",
"Igravesmall",
"Iacutesmall",
"Icircumflexsmall",
"Idieresissmall",
"Ethsmall",
"Ntildesmall",
"Ogravesmall",
"Oacutesmall",
"Ocircumflexsmall",
"Otildesmall",
"Odieresissmall",
"OEsmall",
"Oslashsmall",
"Ugravesmall",
"Uacutesmall",
"Ucircumflexsmall",
"Udieresissmall",
"Yacutesmall",
"Thornsmall",
"Ydieresissmall",
"001.000",
"001.001",
"001.002",
"001.003",
"Black",
"Bold",
"Book",
"Light",
"Medium",
"Regular",
"Roman",
"Semibold",
];

View File

@@ -0,0 +1,47 @@
use crate::parser::{NumFrom, Stream};
use crate::GlyphId;
/// A [format 0](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-0-byte-encoding-table)
/// subtable.
#[derive(Clone, Copy, Debug)]
pub struct Subtable0<'a> {
/// Just a list of 256 8bit glyph IDs.
pub glyph_ids: &'a [u8],
}
impl<'a> Subtable0<'a> {
/// Parses a subtable from raw data.
pub fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
s.skip::<u16>(); // format
s.skip::<u16>(); // length
s.skip::<u16>(); // language
let glyph_ids = s.read_bytes(256)?;
Some(Self { glyph_ids })
}
/// Returns a glyph index for a code point.
pub fn glyph_index(&self, code_point: u32) -> Option<GlyphId> {
let glyph_id = *self.glyph_ids.get(usize::num_from(code_point))?;
// Make sure that the glyph is not zero, the array always has 256 ids,
// but some codepoints may be mapped to zero.
if glyph_id != 0 {
Some(GlyphId(u16::from(glyph_id)))
} else {
None
}
}
/// Calls `f` for each codepoint defined in this table.
pub fn codepoints(&self, mut f: impl FnMut(u32)) {
for (i, glyph_id) in self.glyph_ids.iter().enumerate() {
// In contrast to every other format, here we take a look at the glyph
// id and check whether it is zero because otherwise this method would
// always simply call `f` for `0..256` which would be kind of pointless
// (this array always has length 256 even when the face has fewer glyphs).
if *glyph_id != 0 {
f(i as u32);
}
}
}
}

View File

@@ -0,0 +1,45 @@
use crate::parser::{LazyArray32, Stream};
use crate::GlyphId;
/// A [format 10](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-10-trimmed-array)
/// subtable.
#[derive(Clone, Copy, Debug)]
pub struct Subtable10<'a> {
/// First character code covered.
pub first_code_point: u32,
/// Array of glyph indices for the character codes covered.
pub glyphs: LazyArray32<'a, GlyphId>,
}
impl<'a> Subtable10<'a> {
/// Parses a subtable from raw data.
pub fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
s.skip::<u16>(); // format
s.skip::<u16>(); // reserved
s.skip::<u32>(); // length
s.skip::<u32>(); // language
let first_code_point = s.read::<u32>()?;
let count = s.read::<u32>()?;
let glyphs = s.read_array32::<GlyphId>(count)?;
Some(Self {
first_code_point,
glyphs,
})
}
/// Returns a glyph index for a code point.
pub fn glyph_index(&self, code_point: u32) -> Option<GlyphId> {
let idx = code_point.checked_sub(self.first_code_point)?;
self.glyphs.get(idx)
}
/// Calls `f` for each codepoint defined in this table.
pub fn codepoints(&self, mut f: impl FnMut(u32)) {
for i in 0..self.glyphs.len() {
if let Some(code_point) = self.first_code_point.checked_add(i) {
f(code_point);
}
}
}
}

View File

@@ -0,0 +1,82 @@
use core::convert::TryFrom;
use crate::parser::{FromData, LazyArray32, Stream};
use crate::GlyphId;
#[derive(Clone, Copy)]
pub struct SequentialMapGroup {
pub start_char_code: u32,
pub end_char_code: u32,
pub start_glyph_id: u32,
}
impl FromData for SequentialMapGroup {
const SIZE: usize = 12;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(SequentialMapGroup {
start_char_code: s.read::<u32>()?,
end_char_code: s.read::<u32>()?,
start_glyph_id: s.read::<u32>()?,
})
}
}
/// A [format 12](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-12-segmented-coverage)
/// subtable.
#[derive(Clone, Copy)]
pub struct Subtable12<'a> {
groups: LazyArray32<'a, SequentialMapGroup>,
}
impl<'a> Subtable12<'a> {
/// Parses a subtable from raw data.
pub fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
s.skip::<u16>(); // format
s.skip::<u16>(); // reserved
s.skip::<u32>(); // length
s.skip::<u32>(); // language
let count = s.read::<u32>()?;
let groups = s.read_array32::<SequentialMapGroup>(count)?;
Some(Self { groups })
}
/// Returns a glyph index for a code point.
pub fn glyph_index(&self, code_point: u32) -> Option<GlyphId> {
let (_, group) = self.groups.binary_search_by(|range| {
use core::cmp::Ordering;
if range.start_char_code > code_point {
Ordering::Greater
} else if range.end_char_code < code_point {
Ordering::Less
} else {
Ordering::Equal
}
})?;
let id = group
.start_glyph_id
.checked_add(code_point)?
.checked_sub(group.start_char_code)?;
u16::try_from(id).ok().map(GlyphId)
}
/// Calls `f` for each codepoint defined in this table.
pub fn codepoints(&self, mut f: impl FnMut(u32)) {
for group in self.groups {
for code_point in group.start_char_code..=group.end_char_code {
f(code_point);
}
}
}
}
impl core::fmt::Debug for Subtable12<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Subtable12 {{ ... }}")
}
}

View File

@@ -0,0 +1,55 @@
// https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-13-many-to-one-range-mappings
use core::convert::TryFrom;
use super::format12::SequentialMapGroup;
use crate::parser::{LazyArray32, Stream};
use crate::GlyphId;
/// A [format 13](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-13-segmented-coverage)
/// subtable.
#[derive(Clone, Copy)]
pub struct Subtable13<'a> {
groups: LazyArray32<'a, SequentialMapGroup>,
}
impl<'a> Subtable13<'a> {
/// Parses a subtable from raw data.
pub fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
s.skip::<u16>(); // format
s.skip::<u16>(); // reserved
s.skip::<u32>(); // length
s.skip::<u32>(); // language
let count = s.read::<u32>()?;
let groups = s.read_array32::<super::format12::SequentialMapGroup>(count)?;
Some(Self { groups })
}
/// Returns a glyph index for a code point.
pub fn glyph_index(&self, code_point: u32) -> Option<GlyphId> {
for group in self.groups {
let start_char_code = group.start_char_code;
if code_point >= start_char_code && code_point <= group.end_char_code {
return u16::try_from(group.start_glyph_id).ok().map(GlyphId);
}
}
None
}
/// Calls `f` for each codepoint defined in this table.
pub fn codepoints(&self, mut f: impl FnMut(u32)) {
for group in self.groups {
for code_point in group.start_char_code..=group.end_char_code {
f(code_point);
}
}
}
}
impl core::fmt::Debug for Subtable13<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Subtable13 {{ ... }}")
}
}

View File

@@ -0,0 +1,139 @@
use crate::parser::{FromData, LazyArray32, Offset, Offset32, Stream, U24};
use crate::GlyphId;
#[derive(Clone, Copy)]
struct VariationSelectorRecord {
var_selector: u32,
default_uvs_offset: Option<Offset32>,
non_default_uvs_offset: Option<Offset32>,
}
impl FromData for VariationSelectorRecord {
const SIZE: usize = 11;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(VariationSelectorRecord {
var_selector: s.read::<U24>()?.0,
default_uvs_offset: s.read::<Option<Offset32>>()?,
non_default_uvs_offset: s.read::<Option<Offset32>>()?,
})
}
}
#[derive(Clone, Copy)]
struct UVSMappingRecord {
unicode_value: u32,
glyph_id: GlyphId,
}
impl FromData for UVSMappingRecord {
const SIZE: usize = 5;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(UVSMappingRecord {
unicode_value: s.read::<U24>()?.0,
glyph_id: s.read::<GlyphId>()?,
})
}
}
#[derive(Clone, Copy)]
struct UnicodeRangeRecord {
start_unicode_value: u32,
additional_count: u8,
}
impl UnicodeRangeRecord {
fn contains(&self, c: u32) -> bool {
// Never overflows, since `start_unicode_value` is actually u24.
let end = self.start_unicode_value + u32::from(self.additional_count);
(self.start_unicode_value..=end).contains(&c)
}
}
impl FromData for UnicodeRangeRecord {
const SIZE: usize = 4;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(UnicodeRangeRecord {
start_unicode_value: s.read::<U24>()?.0,
additional_count: s.read::<u8>()?,
})
}
}
/// A result of a variation glyph mapping.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum GlyphVariationResult {
/// Glyph was found in the variation encoding table.
Found(GlyphId),
/// Glyph should be looked in other, non-variation tables.
///
/// Basically, you should use `Encoding::glyph_index` or `Face::glyph_index`
/// in this case.
UseDefault,
}
/// A [format 14](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-14-unicode-variation-sequences)
/// subtable.
#[derive(Clone, Copy)]
pub struct Subtable14<'a> {
records: LazyArray32<'a, VariationSelectorRecord>,
// The whole subtable data.
data: &'a [u8],
}
impl<'a> Subtable14<'a> {
/// Parses a subtable from raw data.
pub fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
s.skip::<u16>(); // format
s.skip::<u32>(); // length
let count = s.read::<u32>()?;
let records = s.read_array32::<VariationSelectorRecord>(count)?;
Some(Self { records, data })
}
/// Returns a glyph index for a code point.
pub fn glyph_index(&self, code_point: u32, variation: u32) -> Option<GlyphVariationResult> {
let (_, record) = self
.records
.binary_search_by(|v| v.var_selector.cmp(&variation))?;
if let Some(offset) = record.default_uvs_offset {
let data = self.data.get(offset.to_usize()..)?;
let mut s = Stream::new(data);
let count = s.read::<u32>()?;
let ranges = s.read_array32::<UnicodeRangeRecord>(count)?;
for range in ranges {
if range.contains(code_point) {
return Some(GlyphVariationResult::UseDefault);
}
}
}
if let Some(offset) = record.non_default_uvs_offset {
let data = self.data.get(offset.to_usize()..)?;
let mut s = Stream::new(data);
let count = s.read::<u32>()?;
let uvs_mappings = s.read_array32::<UVSMappingRecord>(count)?;
let (_, mapping) =
uvs_mappings.binary_search_by(|v| v.unicode_value.cmp(&code_point))?;
return Some(GlyphVariationResult::Found(mapping.glyph_id));
}
None
}
}
impl core::fmt::Debug for Subtable14<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Subtable14 {{ ... }}")
}
}

View File

@@ -0,0 +1,158 @@
// This table has a pretty complex parsing algorithm.
// A detailed explanation can be found here:
// https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-2-high-byte-mapping-through-table
// https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6cmap.html
// https://github.com/fonttools/fonttools/blob/a360252709a3d65f899915db0a5bd753007fdbb7/Lib/fontTools/ttLib/tables/_c_m_a_p.py#L360
use core::convert::TryFrom;
use crate::parser::{FromData, LazyArray16, Stream};
use crate::GlyphId;
#[derive(Clone, Copy)]
struct SubHeaderRecord {
first_code: u16,
entry_count: u16,
id_delta: i16,
id_range_offset: u16,
}
impl FromData for SubHeaderRecord {
const SIZE: usize = 8;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(SubHeaderRecord {
first_code: s.read::<u16>()?,
entry_count: s.read::<u16>()?,
id_delta: s.read::<i16>()?,
id_range_offset: s.read::<u16>()?,
})
}
}
/// A [format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-2-high-byte-mapping-through-table)
/// subtable.
#[derive(Clone, Copy)]
pub struct Subtable2<'a> {
sub_header_keys: LazyArray16<'a, u16>,
sub_headers_offset: usize,
sub_headers: LazyArray16<'a, SubHeaderRecord>,
// The whole subtable data.
data: &'a [u8],
}
impl<'a> Subtable2<'a> {
/// Parses a subtable from raw data.
pub fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
s.skip::<u16>(); // format
s.skip::<u16>(); // length
s.skip::<u16>(); // language
let sub_header_keys = s.read_array16::<u16>(256)?;
// The maximum index in a sub_header_keys is a sub_headers count.
let sub_headers_count = sub_header_keys.into_iter().map(|n| n / 8).max()? + 1;
// Remember sub_headers offset before reading. Will be used later.
let sub_headers_offset = s.offset();
let sub_headers = s.read_array16::<SubHeaderRecord>(sub_headers_count)?;
Some(Self {
sub_header_keys,
sub_headers_offset,
sub_headers,
data,
})
}
/// Returns a glyph index for a code point.
///
/// Returns `None` when `code_point` is larger than `u16`.
pub fn glyph_index(&self, code_point: u32) -> Option<GlyphId> {
// This subtable supports code points only in a u16 range.
let code_point = u16::try_from(code_point).ok()?;
let code_point = code_point;
let high_byte = code_point >> 8;
let low_byte = code_point & 0x00FF;
let i = if code_point < 0xff {
// 'SubHeader 0 is special: it is used for single-byte character codes.'
0
} else {
// 'Array that maps high bytes to subHeaders: value is subHeader index × 8.'
self.sub_header_keys.get(high_byte)? / 8
};
let sub_header = self.sub_headers.get(i)?;
let first_code = sub_header.first_code;
let range_end = first_code.checked_add(sub_header.entry_count)?;
if low_byte < first_code || low_byte >= range_end {
return None;
}
// SubHeaderRecord::id_range_offset points to SubHeaderRecord::first_code
// in the glyphIndexArray. So we have to advance to our code point.
let index_offset = usize::from(low_byte.checked_sub(first_code)?) * u16::SIZE;
// 'The value of the idRangeOffset is the number of bytes
// past the actual location of the idRangeOffset'.
let offset = self.sub_headers_offset
// Advance to required subheader.
+ SubHeaderRecord::SIZE * usize::from(i + 1)
// Move back to idRangeOffset start.
- u16::SIZE
// Use defined offset.
+ usize::from(sub_header.id_range_offset)
// Advance to required index in the glyphIndexArray.
+ index_offset;
let glyph: u16 = Stream::read_at(self.data, offset)?;
if glyph == 0 {
return None;
}
u16::try_from((i32::from(glyph) + i32::from(sub_header.id_delta)) % 65536)
.ok()
.map(GlyphId)
}
/// Calls `f` for each codepoint defined in this table.
pub fn codepoints(&self, f: impl FnMut(u32)) {
let _ = self.codepoints_inner(f);
}
#[inline]
fn codepoints_inner(&self, mut f: impl FnMut(u32)) -> Option<()> {
for first_byte in 0u16..256 {
let i = self.sub_header_keys.get(first_byte)? / 8;
let sub_header = self.sub_headers.get(i)?;
let first_code = sub_header.first_code;
if i == 0 {
// This is a single byte code.
let range_end = first_code.checked_add(sub_header.entry_count)?;
if first_byte >= first_code && first_byte < range_end {
f(u32::from(first_byte));
}
} else {
// This is a two byte code.
let base = first_code.checked_add(first_byte << 8)?;
for k in 0..sub_header.entry_count {
let code_point = base.checked_add(k)?;
f(u32::from(code_point));
}
}
}
Some(())
}
}
impl core::fmt::Debug for Subtable2<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Subtable2 {{ ... }}")
}
}

View File

@@ -0,0 +1,122 @@
use core::convert::TryFrom;
use crate::parser::{LazyArray16, Stream};
use crate::GlyphId;
/// A [format 4](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-4-segment-mapping-to-delta-values)
/// subtable.
#[derive(Clone, Copy)]
pub struct Subtable4<'a> {
start_codes: LazyArray16<'a, u16>,
end_codes: LazyArray16<'a, u16>,
id_deltas: LazyArray16<'a, i16>,
id_range_offsets: LazyArray16<'a, u16>,
id_range_offset_pos: usize,
// The whole subtable data.
data: &'a [u8],
}
impl<'a> Subtable4<'a> {
/// Parses a subtable from raw data.
pub fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
s.advance(6); // format + length + language
let seg_count_x2 = s.read::<u16>()?;
if seg_count_x2 < 2 {
return None;
}
let seg_count = seg_count_x2 / 2;
s.advance(6); // searchRange + entrySelector + rangeShift
let end_codes = s.read_array16::<u16>(seg_count)?;
s.skip::<u16>(); // reservedPad
let start_codes = s.read_array16::<u16>(seg_count)?;
let id_deltas = s.read_array16::<i16>(seg_count)?;
let id_range_offset_pos = s.offset();
let id_range_offsets = s.read_array16::<u16>(seg_count)?;
Some(Self {
start_codes,
end_codes,
id_deltas,
id_range_offsets,
id_range_offset_pos,
data,
})
}
/// Returns a glyph index for a code point.
///
/// Returns `None` when `code_point` is larger than `u16`.
pub fn glyph_index(&self, code_point: u32) -> Option<GlyphId> {
// This subtable supports code points only in a u16 range.
let code_point = u16::try_from(code_point).ok()?;
// A custom binary search.
let mut start = 0;
let mut end = self.start_codes.len();
while end > start {
let index = (start + end) / 2;
let end_value = self.end_codes.get(index)?;
if end_value >= code_point {
let start_value = self.start_codes.get(index)?;
if start_value > code_point {
end = index;
} else {
let id_range_offset = self.id_range_offsets.get(index)?;
let id_delta = self.id_deltas.get(index)?;
if id_range_offset == 0 {
return Some(GlyphId(code_point.wrapping_add(id_delta as u16)));
} else if id_range_offset == 0xFFFF {
// Some malformed fonts have 0xFFFF as the last offset,
// which is invalid and should be ignored.
return None;
}
let delta = (u32::from(code_point) - u32::from(start_value)) * 2;
let delta = u16::try_from(delta).ok()?;
let id_range_offset_pos =
(self.id_range_offset_pos + usize::from(index) * 2) as u16;
let pos = id_range_offset_pos.wrapping_add(delta);
let pos = pos.wrapping_add(id_range_offset);
let glyph_array_value: u16 = Stream::read_at(self.data, usize::from(pos))?;
// 0 indicates missing glyph.
if glyph_array_value == 0 {
return None;
}
let glyph_id = (glyph_array_value as i16).wrapping_add(id_delta);
return u16::try_from(glyph_id).ok().map(GlyphId);
}
} else {
start = index + 1;
}
}
None
}
/// Calls `f` for each codepoint defined in this table.
pub fn codepoints(&self, mut f: impl FnMut(u32)) {
for (start, end) in self.start_codes.into_iter().zip(self.end_codes) {
// OxFFFF value is special and indicates codes end.
if start == end && start == 0xFFFF {
break;
}
for code_point in start..=end {
f(u32::from(code_point));
}
}
}
}
impl core::fmt::Debug for Subtable4<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Subtable4 {{ ... }}")
}
}

View File

@@ -0,0 +1,50 @@
use core::convert::TryFrom;
use crate::parser::{LazyArray16, Stream};
use crate::GlyphId;
/// A [format 6](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-6-trimmed-table-mapping)
/// subtable.
#[derive(Clone, Copy, Debug)]
pub struct Subtable6<'a> {
/// First character code of subrange.
pub first_code_point: u16,
/// Array of glyph indexes for character codes in the range.
pub glyphs: LazyArray16<'a, GlyphId>,
}
impl<'a> Subtable6<'a> {
/// Parses a subtable from raw data.
pub fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
s.skip::<u16>(); // format
s.skip::<u16>(); // length
s.skip::<u16>(); // language
let first_code_point = s.read::<u16>()?;
let count = s.read::<u16>()?;
let glyphs = s.read_array16::<GlyphId>(count)?;
Some(Self {
first_code_point,
glyphs,
})
}
/// Returns a glyph index for a code point.
///
/// Returns `None` when `code_point` is larger than `u16`.
pub fn glyph_index(&self, code_point: u32) -> Option<GlyphId> {
// This subtable supports code points only in a u16 range.
let code_point = u16::try_from(code_point).ok()?;
let idx = code_point.checked_sub(self.first_code_point)?;
self.glyphs.get(idx)
}
/// Calls `f` for each codepoint defined in this table.
pub fn codepoints(&self, mut f: impl FnMut(u32)) {
for i in 0..self.glyphs.len() {
if let Some(code_point) = self.first_code_point.checked_add(i) {
f(u32::from(code_point));
}
}
}
}

284
vendor/ttf-parser/src/tables/cmap/mod.rs vendored Normal file
View File

@@ -0,0 +1,284 @@
/*!
A [Character to Glyph Index Mapping Table](
https://docs.microsoft.com/en-us/typography/opentype/spec/cmap) implementation.
This module provides a low-level alternative to
[`Face::glyph_index`](../struct.Face.html#method.glyph_index) and
[`Face::glyph_variation_index`](../struct.Face.html#method.glyph_variation_index)
methods.
*/
use crate::parser::{FromData, LazyArray16, Offset, Offset32, Stream};
use crate::{name::PlatformId, GlyphId};
mod format0;
mod format10;
mod format12;
mod format13;
mod format14;
mod format2;
mod format4;
mod format6;
pub use format0::Subtable0;
pub use format10::Subtable10;
pub use format12::Subtable12;
pub use format13::Subtable13;
pub use format14::{GlyphVariationResult, Subtable14};
pub use format2::Subtable2;
pub use format4::Subtable4;
pub use format6::Subtable6;
/// A character encoding subtable variant.
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug)]
pub enum Format<'a> {
ByteEncodingTable(Subtable0<'a>),
HighByteMappingThroughTable(Subtable2<'a>),
SegmentMappingToDeltaValues(Subtable4<'a>),
TrimmedTableMapping(Subtable6<'a>),
MixedCoverage, // unsupported
TrimmedArray(Subtable10<'a>),
SegmentedCoverage(Subtable12<'a>),
ManyToOneRangeMappings(Subtable13<'a>),
UnicodeVariationSequences(Subtable14<'a>),
}
/// A character encoding subtable.
#[derive(Clone, Copy, Debug)]
pub struct Subtable<'a> {
/// Subtable platform.
pub platform_id: PlatformId,
/// Subtable encoding.
pub encoding_id: u16,
/// A subtable format.
pub format: Format<'a>,
}
impl<'a> Subtable<'a> {
/// Checks that the current encoding is Unicode compatible.
#[inline]
pub fn is_unicode(&self) -> bool {
// https://docs.microsoft.com/en-us/typography/opentype/spec/name#windows-encoding-ids
const WINDOWS_UNICODE_BMP_ENCODING_ID: u16 = 1;
const WINDOWS_UNICODE_FULL_REPERTOIRE_ENCODING_ID: u16 = 10;
match self.platform_id {
PlatformId::Unicode => true,
PlatformId::Windows if self.encoding_id == WINDOWS_UNICODE_BMP_ENCODING_ID => true,
PlatformId::Windows => {
// "Note: Subtable format 13 has the same structure as format 12; it differs only
// in the interpretation of the startGlyphID/glyphID fields".
let is_format_12_compatible = matches!(
self.format,
Format::SegmentedCoverage(..) | Format::ManyToOneRangeMappings(..)
);
// "Fonts that support Unicode supplementary-plane characters (U+10000 to U+10FFFF)
// on the Windows platform must have a format 12 subtable for platform ID 3,
// encoding ID 10."
self.encoding_id == WINDOWS_UNICODE_FULL_REPERTOIRE_ENCODING_ID
&& is_format_12_compatible
}
_ => false,
}
}
/// Maps a character to a glyph ID.
///
/// This is a low-level method and unlike `Face::glyph_index` it doesn't
/// check that the current encoding is Unicode.
/// It simply maps a `u32` codepoint number to a glyph ID.
///
/// Returns `None`:
/// - when glyph ID is `0`.
/// - when format is `MixedCoverage`, since it's not supported.
/// - when format is `UnicodeVariationSequences`. Use `glyph_variation_index` instead.
#[inline]
pub fn glyph_index(&self, code_point: u32) -> Option<GlyphId> {
match self.format {
Format::ByteEncodingTable(ref subtable) => subtable.glyph_index(code_point),
Format::HighByteMappingThroughTable(ref subtable) => subtable.glyph_index(code_point),
Format::SegmentMappingToDeltaValues(ref subtable) => subtable.glyph_index(code_point),
Format::TrimmedTableMapping(ref subtable) => subtable.glyph_index(code_point),
Format::MixedCoverage => None,
Format::TrimmedArray(ref subtable) => subtable.glyph_index(code_point),
Format::SegmentedCoverage(ref subtable) => subtable.glyph_index(code_point),
Format::ManyToOneRangeMappings(ref subtable) => subtable.glyph_index(code_point),
// This subtable should be accessed via glyph_variation_index().
Format::UnicodeVariationSequences(_) => None,
}
}
/// Resolves a variation of a glyph ID from two code points.
///
/// Returns `None`:
/// - when glyph ID is `0`.
/// - when format is not `UnicodeVariationSequences`.
#[inline]
pub fn glyph_variation_index(
&self,
code_point: u32,
variation: u32,
) -> Option<GlyphVariationResult> {
match self.format {
Format::UnicodeVariationSequences(ref subtable) => {
subtable.glyph_index(code_point, variation)
}
_ => None,
}
}
/// Calls `f` for all codepoints contained in this subtable.
///
/// This is a low-level method and it doesn't check that the current
/// encoding is Unicode. It simply calls the function `f` for all `u32`
/// codepoints that are present in this subtable.
///
/// Note that this may list codepoints for which `glyph_index` still returns
/// `None` because this method finds all codepoints which were _defined_ in
/// this subtable. The subtable may still map them to glyph ID `0`.
///
/// Returns without doing anything:
/// - when format is `MixedCoverage`, since it's not supported.
/// - when format is `UnicodeVariationSequences`, since it's not supported.
pub fn codepoints<F: FnMut(u32)>(&self, f: F) {
match self.format {
Format::ByteEncodingTable(ref subtable) => subtable.codepoints(f),
Format::HighByteMappingThroughTable(ref subtable) => subtable.codepoints(f),
Format::SegmentMappingToDeltaValues(ref subtable) => subtable.codepoints(f),
Format::TrimmedTableMapping(ref subtable) => subtable.codepoints(f),
Format::MixedCoverage => {} // unsupported
Format::TrimmedArray(ref subtable) => subtable.codepoints(f),
Format::SegmentedCoverage(ref subtable) => subtable.codepoints(f),
Format::ManyToOneRangeMappings(ref subtable) => subtable.codepoints(f),
Format::UnicodeVariationSequences(_) => {} // unsupported
};
}
}
#[derive(Clone, Copy)]
struct EncodingRecord {
platform_id: PlatformId,
encoding_id: u16,
offset: Offset32,
}
impl FromData for EncodingRecord {
const SIZE: usize = 8;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(EncodingRecord {
platform_id: s.read::<PlatformId>()?,
encoding_id: s.read::<u16>()?,
offset: s.read::<Offset32>()?,
})
}
}
/// A list of subtables.
#[derive(Clone, Copy, Default)]
pub struct Subtables<'a> {
data: &'a [u8],
records: LazyArray16<'a, EncodingRecord>,
}
impl core::fmt::Debug for Subtables<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Subtables {{ ... }}")
}
}
impl<'a> Subtables<'a> {
/// Returns a subtable at an index.
pub fn get(&self, index: u16) -> Option<Subtable<'a>> {
let record = self.records.get(index)?;
let data = self.data.get(record.offset.to_usize()..)?;
let format = match Stream::read_at::<u16>(data, 0)? {
0 => Format::ByteEncodingTable(Subtable0::parse(data)?),
2 => Format::HighByteMappingThroughTable(Subtable2::parse(data)?),
4 => Format::SegmentMappingToDeltaValues(Subtable4::parse(data)?),
6 => Format::TrimmedTableMapping(Subtable6::parse(data)?),
8 => Format::MixedCoverage, // unsupported
10 => Format::TrimmedArray(Subtable10::parse(data)?),
12 => Format::SegmentedCoverage(Subtable12::parse(data)?),
13 => Format::ManyToOneRangeMappings(Subtable13::parse(data)?),
14 => Format::UnicodeVariationSequences(Subtable14::parse(data)?),
_ => return None,
};
Some(Subtable {
platform_id: record.platform_id,
encoding_id: record.encoding_id,
format,
})
}
/// Returns the number of subtables.
#[inline]
pub fn len(&self) -> u16 {
self.records.len()
}
/// Checks if there are any subtables.
pub fn is_empty(&self) -> bool {
self.records.is_empty()
}
}
impl<'a> IntoIterator for Subtables<'a> {
type Item = Subtable<'a>;
type IntoIter = SubtablesIter<'a>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
SubtablesIter {
subtables: self,
index: 0,
}
}
}
/// An iterator over [`Subtables`].
#[allow(missing_debug_implementations)]
pub struct SubtablesIter<'a> {
subtables: Subtables<'a>,
index: u16,
}
impl<'a> Iterator for SubtablesIter<'a> {
type Item = Subtable<'a>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.index < self.subtables.len() {
self.index += 1;
self.subtables.get(self.index - 1)
} else {
None
}
}
}
/// A [Character to Glyph Index Mapping Table](
/// https://docs.microsoft.com/en-us/typography/opentype/spec/cmap).
#[derive(Clone, Copy, Debug)]
pub struct Table<'a> {
/// A list of subtables.
pub subtables: Subtables<'a>,
}
impl<'a> Table<'a> {
/// Parses a table from raw data.
pub fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
s.skip::<u16>(); // version
let count = s.read::<u16>()?;
let records = s.read_array16::<EncodingRecord>(count)?;
Some(Table {
subtables: Subtables { data, records },
})
}
}

1907
vendor/ttf-parser/src/tables/colr.rs vendored Normal file

File diff suppressed because it is too large Load Diff

90
vendor/ttf-parser/src/tables/cpal.rs vendored Normal file
View File

@@ -0,0 +1,90 @@
//! A [Color Palette Table](
//! https://docs.microsoft.com/en-us/typography/opentype/spec/cpal) implementation.
use core::num::NonZeroU16;
use crate::parser::{FromData, LazyArray16, Offset, Offset32, Stream};
use crate::RgbaColor;
/// A [Color Palette Table](
/// https://docs.microsoft.com/en-us/typography/opentype/spec/cpal).
#[derive(Clone, Copy, Debug)]
pub struct Table<'a> {
color_indices: LazyArray16<'a, u16>,
colors: LazyArray16<'a, BgraColor>,
}
impl<'a> Table<'a> {
/// Parses a table from raw data.
pub fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let version = s.read::<u16>()?;
if version > 1 {
return None;
}
s.skip::<u16>(); // number of palette entries
let num_palettes = s.read::<u16>()?;
if num_palettes == 0 {
return None; // zero palettes is an error
}
let num_colors = s.read::<u16>()?;
let color_records_offset = s.read::<Offset32>()?;
let color_indices = s.read_array16::<u16>(num_palettes)?;
let colors = Stream::new_at(data, color_records_offset.to_usize())?
.read_array16::<BgraColor>(num_colors)?;
Some(Self {
color_indices,
colors,
})
}
/// Returns the number of palettes.
pub fn palettes(&self) -> NonZeroU16 {
// Already checked during parsing.
NonZeroU16::new(self.color_indices.len() as u16).unwrap()
}
/// Returns the color at the given index into the given palette.
pub fn get(&self, palette_index: u16, palette_entry: u16) -> Option<RgbaColor> {
let index = self
.color_indices
.get(palette_index)?
.checked_add(palette_entry)?;
self.colors.get(index).map(|c| c.to_rgba())
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
struct BgraColor {
blue: u8,
green: u8,
red: u8,
alpha: u8,
}
impl BgraColor {
#[inline]
fn to_rgba(self) -> RgbaColor {
RgbaColor::new(self.red, self.green, self.blue, self.alpha)
}
}
impl FromData for BgraColor {
const SIZE: usize = 4;
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(Self {
blue: s.read::<u8>()?,
green: s.read::<u8>()?,
red: s.read::<u8>()?,
alpha: s.read::<u8>()?,
})
}
}

183
vendor/ttf-parser/src/tables/feat.rs vendored Normal file
View File

@@ -0,0 +1,183 @@
//! A [Feature Name Table](
//! https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6feat.html) implementation.
use crate::parser::{FromData, LazyArray16, Offset, Offset32, Stream};
#[derive(Clone, Copy, Debug)]
struct FeatureNameRecord {
feature: u16,
setting_table_records_count: u16,
// Offset from the beginning of the table.
setting_table_offset: Offset32,
flags: u8,
default_setting_index: u8,
name_index: u16,
}
impl FromData for FeatureNameRecord {
const SIZE: usize = 12;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(FeatureNameRecord {
feature: s.read::<u16>()?,
setting_table_records_count: s.read::<u16>()?,
setting_table_offset: s.read::<Offset32>()?,
flags: s.read::<u8>()?,
default_setting_index: s.read::<u8>()?,
name_index: s.read::<u16>()?,
})
}
}
/// A setting name.
#[derive(Clone, Copy, Debug)]
pub struct SettingName {
/// The setting.
pub setting: u16,
/// The `name` table index for the feature's name in a 256..32768 range.
pub name_index: u16,
}
impl FromData for SettingName {
const SIZE: usize = 4;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(SettingName {
setting: s.read::<u16>()?,
name_index: s.read::<u16>()?,
})
}
}
/// A feature names.
#[derive(Clone, Copy, Debug)]
pub struct FeatureName<'a> {
/// The feature's ID.
pub feature: u16,
/// The feature's setting names.
pub setting_names: LazyArray16<'a, SettingName>,
/// The index of the default setting in the `setting_names`.
pub default_setting_index: u8,
/// The feature's exclusive settings. If set, the feature settings are mutually exclusive.
pub exclusive: bool,
/// The `name` table index for the feature's name in a 256..32768 range.
pub name_index: u16,
}
/// A list fo feature names.
#[derive(Clone, Copy)]
pub struct FeatureNames<'a> {
data: &'a [u8],
records: LazyArray16<'a, FeatureNameRecord>,
}
impl<'a> FeatureNames<'a> {
/// Returns a feature name at an index.
pub fn get(&self, index: u16) -> Option<FeatureName<'a>> {
let record = self.records.get(index)?;
let data = self.data.get(record.setting_table_offset.to_usize()..)?;
let mut s = Stream::new(data);
let setting_names = s.read_array16::<SettingName>(record.setting_table_records_count)?;
Some(FeatureName {
feature: record.feature,
setting_names,
default_setting_index: if record.flags & 0x40 != 0 {
record.default_setting_index
} else {
0
},
exclusive: record.flags & 0x80 != 0,
name_index: record.name_index,
})
}
/// Finds a feature name by ID.
pub fn find(&self, feature: u16) -> Option<FeatureName<'a>> {
let index = self
.records
.binary_search_by(|name| name.feature.cmp(&feature))
.map(|(i, _)| i)?;
self.get(index)
}
/// Returns the number of feature names.
pub fn len(&self) -> u16 {
self.records.len()
}
/// Checks if there are any feature names.
pub fn is_empty(&self) -> bool {
self.records.is_empty()
}
}
impl<'a> core::fmt::Debug for FeatureNames<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.debug_list().entries(self.into_iter()).finish()
}
}
impl<'a> IntoIterator for FeatureNames<'a> {
type Item = FeatureName<'a>;
type IntoIter = FeatureNamesIter<'a>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
FeatureNamesIter {
names: self,
index: 0,
}
}
}
/// An iterator over [`FeatureNames`].
#[allow(missing_debug_implementations)]
pub struct FeatureNamesIter<'a> {
names: FeatureNames<'a>,
index: u16,
}
impl<'a> Iterator for FeatureNamesIter<'a> {
type Item = FeatureName<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.index < self.names.len() {
self.index += 1;
self.names.get(self.index - 1)
} else {
None
}
}
}
/// A [Feature Name Table](
/// https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6feat.html).
#[derive(Clone, Copy, Debug)]
pub struct Table<'a> {
/// A list of feature names. Sorted by `FeatureName.feature`.
pub names: FeatureNames<'a>,
}
impl<'a> Table<'a> {
/// Parses a table from raw data.
pub fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let version = s.read::<u32>()?;
if version != 0x00010000 {
return None;
}
let count = s.read::<u16>()?;
s.advance_checked(6)?; // reserved
let records = s.read_array16::<FeatureNameRecord>(count)?;
Some(Table {
names: FeatureNames { data, records },
})
}
}

96
vendor/ttf-parser/src/tables/fvar.rs vendored Normal file
View File

@@ -0,0 +1,96 @@
//! A [Font Variations Table](
//! https://docs.microsoft.com/en-us/typography/opentype/spec/fvar) implementation.
use core::num::NonZeroU16;
use crate::parser::{f32_bound, Fixed, FromData, LazyArray16, Offset, Offset16, Stream};
use crate::{NormalizedCoordinate, Tag};
/// A [variation axis](https://docs.microsoft.com/en-us/typography/opentype/spec/fvar#variationaxisrecord).
#[repr(C)]
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct VariationAxis {
pub tag: Tag,
pub min_value: f32,
pub def_value: f32,
pub max_value: f32,
/// An axis name in the `name` table.
pub name_id: u16,
pub hidden: bool,
}
impl FromData for VariationAxis {
const SIZE: usize = 20;
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
let tag = s.read::<Tag>()?;
let min_value = s.read::<Fixed>()?;
let def_value = s.read::<Fixed>()?;
let max_value = s.read::<Fixed>()?;
let flags = s.read::<u16>()?;
let name_id = s.read::<u16>()?;
Some(VariationAxis {
tag,
min_value: def_value.0.min(min_value.0),
def_value: def_value.0,
max_value: def_value.0.max(max_value.0),
name_id,
hidden: (flags >> 3) & 1 == 1,
})
}
}
impl VariationAxis {
/// Returns a normalized variation coordinate for this axis.
pub(crate) fn normalized_value(&self, mut v: f32) -> NormalizedCoordinate {
// Based on
// https://docs.microsoft.com/en-us/typography/opentype/spec/avar#overview
v = f32_bound(self.min_value, v, self.max_value);
if v == self.def_value {
v = 0.0;
} else if v < self.def_value {
v = (v - self.def_value) / (self.def_value - self.min_value);
} else {
v = (v - self.def_value) / (self.max_value - self.def_value);
}
NormalizedCoordinate::from(v)
}
}
/// A [Font Variations Table](
/// https://docs.microsoft.com/en-us/typography/opentype/spec/fvar).
#[derive(Clone, Copy, Debug)]
pub struct Table<'a> {
/// A list of variation axes.
pub axes: LazyArray16<'a, VariationAxis>,
}
impl<'a> Table<'a> {
/// Parses a table from raw data.
pub fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let version = s.read::<u32>()?;
if version != 0x00010000 {
return None;
}
let axes_array_offset = s.read::<Offset16>()?;
s.skip::<u16>(); // reserved
let axis_count = s.read::<u16>()?;
// 'If axisCount is zero, then the font is not functional as a variable font,
// and must be treated as a non-variable font;
// any variation-specific tables or data is ignored.'
let axis_count = NonZeroU16::new(axis_count)?;
let mut s = Stream::new_at(data, axes_array_offset.to_usize())?;
let axes = s.read_array16::<VariationAxis>(axis_count.get())?;
Some(Table { axes })
}
}

190
vendor/ttf-parser/src/tables/gdef.rs vendored Normal file
View File

@@ -0,0 +1,190 @@
//! A [Glyph Definition Table](
//! https://docs.microsoft.com/en-us/typography/opentype/spec/gdef) implementation.
use crate::opentype_layout::{Class, ClassDefinition, Coverage};
use crate::parser::{FromSlice, LazyArray16, Offset, Offset16, Offset32, Stream};
use crate::GlyphId;
#[cfg(feature = "variable-fonts")]
use crate::var_store::ItemVariationStore;
#[cfg(feature = "variable-fonts")]
use crate::NormalizedCoordinate;
/// A [glyph class](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#glyph-class-definition-table).
#[allow(missing_docs)]
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
pub enum GlyphClass {
Base = 1,
Ligature = 2,
Mark = 3,
Component = 4,
}
/// A [Glyph Definition Table](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef).
#[allow(missing_debug_implementations)]
#[derive(Clone, Copy, Default)]
pub struct Table<'a> {
glyph_classes: Option<ClassDefinition<'a>>,
mark_attach_classes: Option<ClassDefinition<'a>>,
mark_glyph_coverage_offsets: Option<(&'a [u8], LazyArray16<'a, Offset32>)>,
#[cfg(feature = "variable-fonts")]
variation_store: Option<ItemVariationStore<'a>>,
}
impl<'a> Table<'a> {
/// Parses a table from raw data.
pub fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let version = s.read::<u32>()?;
if !(version == 0x00010000 || version == 0x00010002 || version == 0x00010003) {
return None;
}
let glyph_class_def_offset = s.read::<Option<Offset16>>()?;
s.skip::<Offset16>(); // attachListOffset
s.skip::<Offset16>(); // ligCaretListOffset
let mark_attach_class_def_offset = s.read::<Option<Offset16>>()?;
let mut mark_glyph_sets_def_offset: Option<Offset16> = None;
if version > 0x00010000 {
mark_glyph_sets_def_offset = s.read::<Option<Offset16>>()?;
}
#[allow(unused_mut)]
#[allow(unused_variables)]
let mut var_store_offset: Option<Offset32> = None;
#[cfg(feature = "variable-fonts")]
{
if version > 0x00010002 {
var_store_offset = s.read::<Option<Offset32>>()?;
}
}
let mut table = Table::default();
if let Some(offset) = glyph_class_def_offset {
if let Some(subdata) = data.get(offset.to_usize()..) {
table.glyph_classes = ClassDefinition::parse(subdata);
}
}
if let Some(offset) = mark_attach_class_def_offset {
if let Some(subdata) = data.get(offset.to_usize()..) {
table.mark_attach_classes = ClassDefinition::parse(subdata);
}
}
if let Some(offset) = mark_glyph_sets_def_offset {
if let Some(subdata) = data.get(offset.to_usize()..) {
let mut s = Stream::new(subdata);
let format = s.read::<u16>()?;
if format == 1 {
if let Some(count) = s.read::<u16>() {
if let Some(array) = s.read_array16::<Offset32>(count) {
table.mark_glyph_coverage_offsets = Some((subdata, array));
}
}
}
}
}
#[cfg(feature = "variable-fonts")]
{
if let Some(offset) = var_store_offset {
if let Some(subdata) = data.get(offset.to_usize()..) {
let s = Stream::new(subdata);
table.variation_store = ItemVariationStore::parse(s);
}
}
}
Some(table)
}
/// Checks that face has
/// [Glyph Class Definition Table](
/// https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#glyph-class-definition-table).
#[inline]
pub fn has_glyph_classes(&self) -> bool {
self.glyph_classes.is_some()
}
/// Returns glyph's class according to
/// [Glyph Class Definition Table](
/// https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#glyph-class-definition-table).
///
/// Returns `None` when *Glyph Class Definition Table* is not set
/// or glyph class is not set or invalid.
#[inline]
pub fn glyph_class(&self, glyph_id: GlyphId) -> Option<GlyphClass> {
match self.glyph_classes?.get(glyph_id) {
1 => Some(GlyphClass::Base),
2 => Some(GlyphClass::Ligature),
3 => Some(GlyphClass::Mark),
4 => Some(GlyphClass::Component),
_ => None,
}
}
/// Returns glyph's mark attachment class according to
/// [Mark Attachment Class Definition Table](
/// https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#mark-attachment-class-definition-table).
///
/// All glyphs not assigned to a class fall into Class 0.
#[inline]
pub fn glyph_mark_attachment_class(&self, glyph_id: GlyphId) -> Class {
self.mark_attach_classes
.map(|def| def.get(glyph_id))
.unwrap_or(0)
}
/// Checks that glyph is a mark according to
/// [Mark Glyph Sets Table](
/// https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#mark-glyph-sets-table).
///
/// `set_index` allows checking a specific glyph coverage set.
/// Otherwise all sets will be checked.
#[inline]
pub fn is_mark_glyph(&self, glyph_id: GlyphId, set_index: Option<u16>) -> bool {
is_mark_glyph_impl(self, glyph_id, set_index).is_some()
}
/// Returns glyph's variation delta at a specified index according to
/// [Item Variation Store Table](
/// https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#item-variation-store-table).
#[cfg(feature = "variable-fonts")]
#[inline]
pub fn glyph_variation_delta(
&self,
outer_index: u16,
inner_index: u16,
coordinates: &[NormalizedCoordinate],
) -> Option<f32> {
self.variation_store
.and_then(|store| store.parse_delta(outer_index, inner_index, coordinates))
}
}
#[inline(never)]
fn is_mark_glyph_impl(table: &Table, glyph_id: GlyphId, set_index: Option<u16>) -> Option<()> {
let (data, offsets) = table.mark_glyph_coverage_offsets?;
if let Some(set_index) = set_index {
if let Some(offset) = offsets.get(set_index) {
let table = Coverage::parse(data.get(offset.to_usize()..)?)?;
if table.contains(glyph_id) {
return Some(());
}
}
} else {
for offset in offsets {
let table = Coverage::parse(data.get(offset.to_usize()..)?)?;
if table.contains(glyph_id) {
return Some(());
}
}
}
None
}

607
vendor/ttf-parser/src/tables/glyf.rs vendored Normal file
View File

@@ -0,0 +1,607 @@
//! A [Glyph Data Table](
//! https://docs.microsoft.com/en-us/typography/opentype/spec/glyf) implementation.
use core::num::NonZeroU16;
use crate::parser::{LazyArray16, NumFrom, Stream, F2DOT14};
use crate::{loca, GlyphId, OutlineBuilder, Rect, RectF, Transform};
pub(crate) struct Builder<'a> {
pub builder: &'a mut dyn OutlineBuilder,
pub transform: Transform,
is_default_ts: bool, // `bool` is faster than `Option` or `is_default`.
// We have to always calculate the bbox, because `gvar` doesn't store one
// and in case of a malformed bbox in `glyf`.
pub bbox: RectF,
first_on_curve: Option<Point>,
first_off_curve: Option<Point>,
last_off_curve: Option<Point>,
}
impl<'a> Builder<'a> {
#[inline]
pub fn new(transform: Transform, bbox: RectF, builder: &'a mut dyn OutlineBuilder) -> Self {
Builder {
builder,
transform,
is_default_ts: transform.is_default(),
bbox,
first_on_curve: None,
first_off_curve: None,
last_off_curve: None,
}
}
#[inline]
fn move_to(&mut self, mut x: f32, mut y: f32) {
if !self.is_default_ts {
self.transform.apply_to(&mut x, &mut y);
}
self.bbox.extend_by(x, y);
self.builder.move_to(x, y);
}
#[inline]
fn line_to(&mut self, mut x: f32, mut y: f32) {
if !self.is_default_ts {
self.transform.apply_to(&mut x, &mut y);
}
self.bbox.extend_by(x, y);
self.builder.line_to(x, y);
}
#[inline]
fn quad_to(&mut self, mut x1: f32, mut y1: f32, mut x: f32, mut y: f32) {
if !self.is_default_ts {
self.transform.apply_to(&mut x1, &mut y1);
self.transform.apply_to(&mut x, &mut y);
}
self.bbox.extend_by(x1, y1);
self.bbox.extend_by(x, y);
self.builder.quad_to(x1, y1, x, y);
}
// Useful links:
//
// - https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html
// - https://stackoverflow.com/a/20772557
#[inline]
pub fn push_point(&mut self, x: f32, y: f32, on_curve_point: bool, last_point: bool) {
let p = Point { x, y };
if self.first_on_curve.is_none() {
if on_curve_point {
self.first_on_curve = Some(p);
self.move_to(p.x, p.y);
} else {
if let Some(offcurve) = self.first_off_curve {
let mid = offcurve.lerp(p, 0.5);
self.first_on_curve = Some(mid);
self.last_off_curve = Some(p);
self.move_to(mid.x, mid.y);
} else {
self.first_off_curve = Some(p);
}
}
} else {
match (self.last_off_curve, on_curve_point) {
(Some(offcurve), true) => {
self.last_off_curve = None;
self.quad_to(offcurve.x, offcurve.y, p.x, p.y);
}
(Some(offcurve), false) => {
self.last_off_curve = Some(p);
let mid = offcurve.lerp(p, 0.5);
self.quad_to(offcurve.x, offcurve.y, mid.x, mid.y);
}
(None, true) => {
self.line_to(p.x, p.y);
}
(None, false) => {
self.last_off_curve = Some(p);
}
}
}
if last_point {
self.finish_contour();
}
}
#[inline]
fn finish_contour(&mut self) {
if let (Some(offcurve1), Some(offcurve2)) = (self.first_off_curve, self.last_off_curve) {
self.last_off_curve = None;
let mid = offcurve2.lerp(offcurve1, 0.5);
self.quad_to(offcurve2.x, offcurve2.y, mid.x, mid.y);
}
if let (Some(p), Some(offcurve1)) = (self.first_on_curve, self.first_off_curve) {
self.quad_to(offcurve1.x, offcurve1.y, p.x, p.y);
} else if let (Some(p), Some(offcurve2)) = (self.first_on_curve, self.last_off_curve) {
self.quad_to(offcurve2.x, offcurve2.y, p.x, p.y);
} else if let Some(p) = self.first_on_curve {
self.line_to(p.x, p.y);
}
self.first_on_curve = None;
self.first_off_curve = None;
self.last_off_curve = None;
self.builder.close();
}
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct CompositeGlyphInfo {
pub glyph_id: GlyphId,
pub transform: Transform,
#[allow(dead_code)]
pub flags: CompositeGlyphFlags,
}
#[derive(Clone)]
pub(crate) struct CompositeGlyphIter<'a> {
stream: Stream<'a>,
}
impl<'a> CompositeGlyphIter<'a> {
#[inline]
pub fn new(data: &'a [u8]) -> Self {
CompositeGlyphIter {
stream: Stream::new(data),
}
}
}
impl<'a> Iterator for CompositeGlyphIter<'a> {
type Item = CompositeGlyphInfo;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let flags = CompositeGlyphFlags(self.stream.read::<u16>()?);
let glyph_id = self.stream.read::<GlyphId>()?;
let mut ts = Transform::default();
if flags.args_are_xy_values() {
if flags.arg_1_and_2_are_words() {
ts.e = f32::from(self.stream.read::<i16>()?);
ts.f = f32::from(self.stream.read::<i16>()?);
} else {
ts.e = f32::from(self.stream.read::<i8>()?);
ts.f = f32::from(self.stream.read::<i8>()?);
}
}
if flags.we_have_a_two_by_two() {
ts.a = self.stream.read::<F2DOT14>()?.to_f32();
ts.b = self.stream.read::<F2DOT14>()?.to_f32();
ts.c = self.stream.read::<F2DOT14>()?.to_f32();
ts.d = self.stream.read::<F2DOT14>()?.to_f32();
} else if flags.we_have_an_x_and_y_scale() {
ts.a = self.stream.read::<F2DOT14>()?.to_f32();
ts.d = self.stream.read::<F2DOT14>()?.to_f32();
} else if flags.we_have_a_scale() {
ts.a = self.stream.read::<F2DOT14>()?.to_f32();
ts.d = ts.a;
}
if !flags.more_components() {
// Finish the iterator even if stream still has some data.
self.stream.jump_to_end();
}
Some(CompositeGlyphInfo {
glyph_id,
transform: ts,
flags,
})
}
}
// Due to some optimization magic, using f32 instead of i16
// makes the code ~10% slower. At least on my machine.
// I guess it's due to the fact that with i16 the struct
// fits into the machine word.
#[derive(Clone, Copy, Debug)]
pub(crate) struct GlyphPoint {
pub x: i16,
pub y: i16,
/// Indicates that a point is a point on curve
/// and not a control point.
pub on_curve_point: bool,
pub last_point: bool,
}
#[derive(Clone, Default)]
pub(crate) struct GlyphPointsIter<'a> {
endpoints: EndpointsIter<'a>,
flags: FlagsIter<'a>,
x_coords: CoordsIter<'a>,
y_coords: CoordsIter<'a>,
pub points_left: u16, // Number of points left in the glyph.
}
#[cfg(feature = "variable-fonts")]
impl GlyphPointsIter<'_> {
#[inline]
pub fn current_contour(&self) -> u16 {
self.endpoints.index - 1
}
}
impl<'a> Iterator for GlyphPointsIter<'a> {
type Item = GlyphPoint;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.points_left = self.points_left.checked_sub(1)?;
// TODO: skip empty contours
let last_point = self.endpoints.next();
let flags = self.flags.next()?;
Some(GlyphPoint {
x: self
.x_coords
.next(flags.x_short(), flags.x_is_same_or_positive_short()),
y: self
.y_coords
.next(flags.y_short(), flags.y_is_same_or_positive_short()),
on_curve_point: flags.on_curve_point(),
last_point,
})
}
}
/// A simple flattening iterator for glyph's endpoints.
///
/// Translates endpoints like: 2 4 7
/// into flags: 0 0 1 0 1 0 0 1
#[derive(Clone, Copy, Default)]
struct EndpointsIter<'a> {
endpoints: LazyArray16<'a, u16>, // Each endpoint indicates a contour end.
index: u16,
left: u16,
}
impl<'a> EndpointsIter<'a> {
#[inline]
fn new(endpoints: LazyArray16<'a, u16>) -> Option<Self> {
Some(EndpointsIter {
endpoints,
index: 1,
left: endpoints.get(0)?,
})
}
#[inline]
fn next(&mut self) -> bool {
if self.left == 0 {
if let Some(end) = self.endpoints.get(self.index) {
let prev = self.endpoints.get(self.index - 1).unwrap_or(0);
// Malformed font can have endpoints not in increasing order,
// so we have to use checked_sub.
self.left = end.saturating_sub(prev);
self.left = self.left.saturating_sub(1);
}
// Always advance the index, so we can check the current contour number.
if let Some(n) = self.index.checked_add(1) {
self.index = n;
}
true
} else {
self.left -= 1;
false
}
}
}
#[derive(Clone, Default)]
struct FlagsIter<'a> {
stream: Stream<'a>,
// Number of times the `flags` should be used
// before reading the next one from `stream`.
repeats: u8,
flags: SimpleGlyphFlags,
}
impl<'a> FlagsIter<'a> {
#[inline]
fn new(data: &'a [u8]) -> Self {
FlagsIter {
stream: Stream::new(data),
repeats: 0,
flags: SimpleGlyphFlags(0),
}
}
}
impl<'a> Iterator for FlagsIter<'a> {
type Item = SimpleGlyphFlags;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.repeats == 0 {
self.flags = SimpleGlyphFlags(self.stream.read::<u8>().unwrap_or(0));
if self.flags.repeat_flag() {
self.repeats = self.stream.read::<u8>().unwrap_or(0);
}
} else {
self.repeats -= 1;
}
Some(self.flags)
}
}
#[derive(Clone, Default)]
struct CoordsIter<'a> {
stream: Stream<'a>,
prev: i16, // Points are stored as deltas, so we have to keep the previous one.
}
impl<'a> CoordsIter<'a> {
#[inline]
fn new(data: &'a [u8]) -> Self {
CoordsIter {
stream: Stream::new(data),
prev: 0,
}
}
#[inline]
fn next(&mut self, is_short: bool, is_same_or_short: bool) -> i16 {
// See https://docs.microsoft.com/en-us/typography/opentype/spec/glyf#simple-glyph-description
// for details about Simple Glyph Flags processing.
// We've already checked the coords data, so it's safe to fallback to 0.
let mut n = 0;
if is_short {
n = i16::from(self.stream.read::<u8>().unwrap_or(0));
if !is_same_or_short {
n = -n;
}
} else if !is_same_or_short {
n = self.stream.read::<i16>().unwrap_or(0);
}
self.prev = self.prev.wrapping_add(n);
self.prev
}
}
#[derive(Clone, Copy, Debug)]
struct Point {
x: f32,
y: f32,
}
impl Point {
#[inline]
fn lerp(self, other: Point, t: f32) -> Point {
Point {
x: self.x + t * (other.x - self.x),
y: self.y + t * (other.y - self.y),
}
}
}
// https://docs.microsoft.com/en-us/typography/opentype/spec/glyf#simple-glyph-description
#[derive(Clone, Copy, Default)]
struct SimpleGlyphFlags(u8);
#[rustfmt::skip]
impl SimpleGlyphFlags {
#[inline] fn on_curve_point(self) -> bool { self.0 & 0x01 != 0 }
#[inline] fn x_short(self) -> bool { self.0 & 0x02 != 0 }
#[inline] fn y_short(self) -> bool { self.0 & 0x04 != 0 }
#[inline] fn repeat_flag(self) -> bool { self.0 & 0x08 != 0 }
#[inline] fn x_is_same_or_positive_short(self) -> bool { self.0 & 0x10 != 0 }
#[inline] fn y_is_same_or_positive_short(self) -> bool { self.0 & 0x20 != 0 }
}
// https://docs.microsoft.com/en-us/typography/opentype/spec/glyf#composite-glyph-description
#[derive(Clone, Copy, Debug)]
pub(crate) struct CompositeGlyphFlags(u16);
#[rustfmt::skip]
impl CompositeGlyphFlags {
#[inline] pub fn arg_1_and_2_are_words(self) -> bool { self.0 & 0x0001 != 0 }
#[inline] pub fn args_are_xy_values(self) -> bool { self.0 & 0x0002 != 0 }
#[inline] pub fn we_have_a_scale(self) -> bool { self.0 & 0x0008 != 0 }
#[inline] pub fn more_components(self) -> bool { self.0 & 0x0020 != 0 }
#[inline] pub fn we_have_an_x_and_y_scale(self) -> bool { self.0 & 0x0040 != 0 }
#[inline] pub fn we_have_a_two_by_two(self) -> bool { self.0 & 0x0080 != 0 }
}
// It's not defined in the spec, so we are using our own value.
pub(crate) const MAX_COMPONENTS: u8 = 32;
#[allow(clippy::comparison_chain)]
#[inline]
fn outline_impl(
loca_table: loca::Table,
glyf_table: &[u8],
data: &[u8],
depth: u8,
builder: &mut Builder,
) -> Option<Option<Rect>> {
if depth >= MAX_COMPONENTS {
return None;
}
let mut s = Stream::new(data);
let number_of_contours = s.read::<i16>()?;
s.advance(8); // Skip bbox. We use calculated one.
if number_of_contours > 0 {
// Simple glyph.
// u16 casting is safe, since we already checked that the value is positive.
let number_of_contours = NonZeroU16::new(number_of_contours as u16)?;
for point in parse_simple_outline(s.tail()?, number_of_contours)? {
builder.push_point(
f32::from(point.x),
f32::from(point.y),
point.on_curve_point,
point.last_point,
);
}
} else if number_of_contours < 0 {
// Composite glyph.
for comp in CompositeGlyphIter::new(s.tail()?) {
if let Some(range) = loca_table.glyph_range(comp.glyph_id) {
if let Some(glyph_data) = glyf_table.get(range) {
let transform = Transform::combine(builder.transform, comp.transform);
let mut b = Builder::new(transform, builder.bbox, builder.builder);
outline_impl(loca_table, glyf_table, glyph_data, depth + 1, &mut b)?;
// Take updated bbox.
builder.bbox = b.bbox;
}
}
}
}
if builder.bbox.is_default() {
return Some(None);
}
Some(builder.bbox.to_rect())
}
#[inline]
pub(crate) fn parse_simple_outline(
glyph_data: &[u8],
number_of_contours: NonZeroU16,
) -> Option<GlyphPointsIter> {
let mut s = Stream::new(glyph_data);
let endpoints = s.read_array16::<u16>(number_of_contours.get())?;
let points_total = endpoints.last()?.checked_add(1)?;
// Contours with a single point should be ignored.
// But this is not an error, so we should return an "empty" iterator.
if points_total == 1 {
return Some(GlyphPointsIter::default());
}
// Skip instructions byte code.
let instructions_len = s.read::<u16>()?;
s.advance(usize::from(instructions_len));
let flags_offset = s.offset();
let (x_coords_len, y_coords_len) = resolve_coords_len(&mut s, points_total)?;
let x_coords_offset = s.offset();
let y_coords_offset = x_coords_offset + usize::num_from(x_coords_len);
let y_coords_end = y_coords_offset + usize::num_from(y_coords_len);
Some(GlyphPointsIter {
endpoints: EndpointsIter::new(endpoints)?,
flags: FlagsIter::new(glyph_data.get(flags_offset..x_coords_offset)?),
x_coords: CoordsIter::new(glyph_data.get(x_coords_offset..y_coords_offset)?),
y_coords: CoordsIter::new(glyph_data.get(y_coords_offset..y_coords_end)?),
points_left: points_total,
})
}
/// Resolves coordinate arrays length.
///
/// The length depends on *Simple Glyph Flags*, so we have to process them all to find it.
fn resolve_coords_len(s: &mut Stream, points_total: u16) -> Option<(u32, u32)> {
let mut flags_left = u32::from(points_total);
let mut repeats;
let mut x_coords_len = 0;
let mut y_coords_len = 0;
while flags_left > 0 {
let flags = SimpleGlyphFlags(s.read::<u8>()?);
// The number of times a glyph point repeats.
repeats = if flags.repeat_flag() {
let repeats = s.read::<u8>()?;
u32::from(repeats) + 1
} else {
1
};
if repeats > flags_left {
return None;
}
// No need to check for `*_coords_len` overflow since u32 is more than enough.
// Non-obfuscated code below.
// Branchless version is surprisingly faster.
//
// if flags.x_short() {
// // Coordinate is 1 byte long.
// x_coords_len += repeats;
// } else if !flags.x_is_same_or_positive_short() {
// // Coordinate is 2 bytes long.
// x_coords_len += repeats * 2;
// }
// if flags.y_short() {
// // Coordinate is 1 byte long.
// y_coords_len += repeats;
// } else if !flags.y_is_same_or_positive_short() {
// // Coordinate is 2 bytes long.
// y_coords_len += repeats * 2;
// }
x_coords_len += (flags.0 & 0x02 != 0) as u32 * repeats;
x_coords_len += (flags.0 & (0x02 | 0x10) == 0) as u32 * (repeats * 2);
y_coords_len += (flags.0 & 0x04 != 0) as u32 * repeats;
y_coords_len += (flags.0 & (0x04 | 0x20) == 0) as u32 * (repeats * 2);
flags_left -= repeats;
}
Some((x_coords_len, y_coords_len))
}
/// A [Glyph Data Table](
/// https://docs.microsoft.com/en-us/typography/opentype/spec/glyf).
#[derive(Clone, Copy)]
pub struct Table<'a> {
pub(crate) data: &'a [u8],
loca_table: loca::Table<'a>,
}
impl core::fmt::Debug for Table<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Table {{ ... }}")
}
}
impl<'a> Table<'a> {
/// Parses a table from raw data.
#[inline]
pub fn parse(loca_table: loca::Table<'a>, data: &'a [u8]) -> Option<Self> {
Some(Table { loca_table, data })
}
/// Outlines a glyph.
#[inline]
pub fn outline(&self, glyph_id: GlyphId, builder: &mut dyn OutlineBuilder) -> Option<Rect> {
let mut b = Builder::new(Transform::default(), RectF::new(), builder);
let glyph_data = self.get(glyph_id)?;
outline_impl(self.loca_table, self.data, glyph_data, 0, &mut b)?
}
#[inline]
pub(crate) fn get(&self, glyph_id: GlyphId) -> Option<&'a [u8]> {
let range = self.loca_table.glyph_range(glyph_id)?;
self.data.get(range)
}
}

1004
vendor/ttf-parser/src/tables/gpos.rs vendored Normal file

File diff suppressed because it is too large Load Diff

292
vendor/ttf-parser/src/tables/gsub.rs vendored Normal file
View File

@@ -0,0 +1,292 @@
//! A [Glyph Substitution Table](https://docs.microsoft.com/en-us/typography/opentype/spec/gsub)
//! implementation.
// A heavily modified port of https://github.com/RazrFalcon/rustybuzz implementation
// originally written by https://github.com/laurmaedje
use crate::opentype_layout::{ChainedContextLookup, ContextLookup, Coverage, LookupSubtable};
use crate::parser::{FromSlice, LazyArray16, LazyOffsetArray16, Stream};
use crate::GlyphId;
/// A [Single Substitution Subtable](https://docs.microsoft.com/en-us/typography/opentype/spec/gsub#SS).
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug)]
pub enum SingleSubstitution<'a> {
Format1 {
coverage: Coverage<'a>,
delta: i16,
},
Format2 {
coverage: Coverage<'a>,
substitutes: LazyArray16<'a, GlyphId>,
},
}
impl<'a> SingleSubstitution<'a> {
fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
match s.read::<u16>()? {
1 => {
let coverage = Coverage::parse(s.read_at_offset16(data)?)?;
let delta = s.read::<i16>()?;
Some(Self::Format1 { coverage, delta })
}
2 => {
let coverage = Coverage::parse(s.read_at_offset16(data)?)?;
let count = s.read::<u16>()?;
let substitutes = s.read_array16(count)?;
Some(Self::Format2 {
coverage,
substitutes,
})
}
_ => None,
}
}
/// Returns the subtable coverage.
#[inline]
pub fn coverage(&self) -> Coverage<'a> {
match self {
Self::Format1 { coverage, .. } => *coverage,
Self::Format2 { coverage, .. } => *coverage,
}
}
}
/// A sequence of glyphs for
/// [Multiple Substitution Subtable](https://docs.microsoft.com/en-us/typography/opentype/spec/gsub#MS).
#[derive(Clone, Copy, Debug)]
pub struct Sequence<'a> {
/// A list of substitute glyphs.
pub substitutes: LazyArray16<'a, GlyphId>,
}
impl<'a> FromSlice<'a> for Sequence<'a> {
fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let count = s.read::<u16>()?;
let substitutes = s.read_array16(count)?;
Some(Self { substitutes })
}
}
/// A list of [`Sequence`] tables.
pub type SequenceList<'a> = LazyOffsetArray16<'a, Sequence<'a>>;
/// A [Multiple Substitution Subtable](https://docs.microsoft.com/en-us/typography/opentype/spec/gsub#MS).
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug)]
pub struct MultipleSubstitution<'a> {
pub coverage: Coverage<'a>,
pub sequences: SequenceList<'a>,
}
impl<'a> MultipleSubstitution<'a> {
fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
match s.read::<u16>()? {
1 => {
let coverage = Coverage::parse(s.read_at_offset16(data)?)?;
let count = s.read::<u16>()?;
let offsets = s.read_array16(count)?;
Some(Self {
coverage,
sequences: SequenceList::new(data, offsets),
})
}
_ => None,
}
}
}
/// A list of glyphs for
/// [Alternate Substitution Subtable](https://docs.microsoft.com/en-us/typography/opentype/spec/gsub#AS).
#[derive(Clone, Copy, Debug)]
pub struct AlternateSet<'a> {
/// Array of alternate glyph IDs, in arbitrary order.
pub alternates: LazyArray16<'a, GlyphId>,
}
impl<'a> FromSlice<'a> for AlternateSet<'a> {
fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let count = s.read::<u16>()?;
let alternates = s.read_array16(count)?;
Some(Self { alternates })
}
}
/// A set of [`AlternateSet`].
pub type AlternateSets<'a> = LazyOffsetArray16<'a, AlternateSet<'a>>;
/// A [Alternate Substitution Subtable](https://docs.microsoft.com/en-us/typography/opentype/spec/gsub#AS).
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug)]
pub struct AlternateSubstitution<'a> {
pub coverage: Coverage<'a>,
pub alternate_sets: AlternateSets<'a>,
}
impl<'a> AlternateSubstitution<'a> {
fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
match s.read::<u16>()? {
1 => {
let coverage = Coverage::parse(s.read_at_offset16(data)?)?;
let count = s.read::<u16>()?;
let offsets = s.read_array16(count)?;
Some(Self {
coverage,
alternate_sets: AlternateSets::new(data, offsets),
})
}
_ => None,
}
}
}
/// Glyph components for one ligature.
#[derive(Clone, Copy, Debug)]
pub struct Ligature<'a> {
/// Ligature to substitute.
pub glyph: GlyphId,
/// Glyph components for one ligature.
pub components: LazyArray16<'a, GlyphId>,
}
impl<'a> FromSlice<'a> for Ligature<'a> {
fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let glyph = s.read::<GlyphId>()?;
let count = s.read::<u16>()?;
let components = s.read_array16(count.checked_sub(1)?)?;
Some(Self { glyph, components })
}
}
/// A [`Ligature`] set.
pub type LigatureSet<'a> = LazyOffsetArray16<'a, Ligature<'a>>;
impl<'a> FromSlice<'a> for LigatureSet<'a> {
fn parse(data: &'a [u8]) -> Option<Self> {
Self::parse(data)
}
}
/// A list of [`Ligature`] sets.
pub type LigatureSets<'a> = LazyOffsetArray16<'a, LigatureSet<'a>>;
/// A [Ligature Substitution Subtable](https://docs.microsoft.com/en-us/typography/opentype/spec/gsub#LS).
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug)]
pub struct LigatureSubstitution<'a> {
pub coverage: Coverage<'a>,
pub ligature_sets: LigatureSets<'a>,
}
impl<'a> LigatureSubstitution<'a> {
fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
match s.read::<u16>()? {
1 => {
let coverage = Coverage::parse(s.read_at_offset16(data)?)?;
let count = s.read::<u16>()?;
let offsets = s.read_array16(count)?;
Some(Self {
coverage,
ligature_sets: LigatureSets::new(data, offsets),
})
}
_ => None,
}
}
}
/// A [Reverse Chaining Contextual Single Substitution Subtable](
/// https://docs.microsoft.com/en-us/typography/opentype/spec/gsub#RCCS).
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug)]
pub struct ReverseChainSingleSubstitution<'a> {
pub coverage: Coverage<'a>,
pub backtrack_coverages: LazyOffsetArray16<'a, Coverage<'a>>,
pub lookahead_coverages: LazyOffsetArray16<'a, Coverage<'a>>,
pub substitutes: LazyArray16<'a, GlyphId>,
}
impl<'a> ReverseChainSingleSubstitution<'a> {
fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
match s.read::<u16>()? {
1 => {
let coverage = Coverage::parse(s.read_at_offset16(data)?)?;
let backtrack_count = s.read::<u16>()?;
let backtrack_coverages = s.read_array16(backtrack_count)?;
let lookahead_count = s.read::<u16>()?;
let lookahead_coverages = s.read_array16(lookahead_count)?;
let substitute_count = s.read::<u16>()?;
let substitutes = s.read_array16(substitute_count)?;
Some(Self {
coverage,
backtrack_coverages: LazyOffsetArray16::new(data, backtrack_coverages),
lookahead_coverages: LazyOffsetArray16::new(data, lookahead_coverages),
substitutes,
})
}
_ => None,
}
}
}
/// A glyph substitution
/// [lookup subtable](https://docs.microsoft.com/en-us/typography/opentype/spec/gsub#table-organization)
/// enumeration.
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug)]
pub enum SubstitutionSubtable<'a> {
Single(SingleSubstitution<'a>),
Multiple(MultipleSubstitution<'a>),
Alternate(AlternateSubstitution<'a>),
Ligature(LigatureSubstitution<'a>),
Context(ContextLookup<'a>),
ChainContext(ChainedContextLookup<'a>),
ReverseChainSingle(ReverseChainSingleSubstitution<'a>),
}
impl<'a> LookupSubtable<'a> for SubstitutionSubtable<'a> {
fn parse(data: &'a [u8], kind: u16) -> Option<Self> {
match kind {
1 => SingleSubstitution::parse(data).map(Self::Single),
2 => MultipleSubstitution::parse(data).map(Self::Multiple),
3 => AlternateSubstitution::parse(data).map(Self::Alternate),
4 => LigatureSubstitution::parse(data).map(Self::Ligature),
5 => ContextLookup::parse(data).map(Self::Context),
6 => ChainedContextLookup::parse(data).map(Self::ChainContext),
7 => crate::ggg::parse_extension_lookup(data, Self::parse),
8 => ReverseChainSingleSubstitution::parse(data).map(Self::ReverseChainSingle),
_ => None,
}
}
}
impl<'a> SubstitutionSubtable<'a> {
/// Returns the subtable coverage.
#[inline]
pub fn coverage(&self) -> Coverage<'a> {
match self {
Self::Single(t) => t.coverage(),
Self::Multiple(t) => t.coverage,
Self::Alternate(t) => t.coverage,
Self::Ligature(t) => t.coverage,
Self::Context(t) => t.coverage(),
Self::ChainContext(t) => t.coverage(),
Self::ReverseChainSingle(t) => t.coverage,
}
}
/// Checks that the current subtable is *Reverse Chaining Contextual Single*.
#[inline]
pub fn is_reverse(&self) -> bool {
matches!(self, Self::ReverseChainSingle(_))
}
}

1917
vendor/ttf-parser/src/tables/gvar.rs vendored Normal file

File diff suppressed because it is too large Load Diff

78
vendor/ttf-parser/src/tables/head.rs vendored Normal file
View File

@@ -0,0 +1,78 @@
//! A [Font Header Table](
//! https://docs.microsoft.com/en-us/typography/opentype/spec/head) implementation.
use crate::parser::{Fixed, Stream};
use crate::Rect;
/// An index format used by the [Index to Location Table](
/// https://docs.microsoft.com/en-us/typography/opentype/spec/loca).
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum IndexToLocationFormat {
Short,
Long,
}
/// A [Font Header Table](https://docs.microsoft.com/en-us/typography/opentype/spec/head).
#[derive(Clone, Copy, Debug)]
pub struct Table {
/// Units per EM.
///
/// Guarantee to be in a 16..=16384 range.
pub units_per_em: u16,
/// A bounding box that large enough to enclose any glyph from the face.
pub global_bbox: Rect,
/// An index format used by the [Index to Location Table](
/// https://docs.microsoft.com/en-us/typography/opentype/spec/loca).
pub index_to_location_format: IndexToLocationFormat,
}
impl Table {
/// Parses a table from raw data.
pub fn parse(data: &[u8]) -> Option<Self> {
// Do not check the exact length, because some fonts include
// padding in table's length in table records, which is incorrect.
if data.len() < 54 {
return None;
}
let mut s = Stream::new(data);
s.skip::<u32>(); // version
s.skip::<Fixed>(); // font revision
s.skip::<u32>(); // checksum adjustment
s.skip::<u32>(); // magic number
s.skip::<u16>(); // flags
let units_per_em = s.read::<u16>()?;
s.skip::<u64>(); // created time
s.skip::<u64>(); // modified time
let x_min = s.read::<i16>()?;
let y_min = s.read::<i16>()?;
let x_max = s.read::<i16>()?;
let y_max = s.read::<i16>()?;
s.skip::<u16>(); // mac style
s.skip::<u16>(); // lowest PPEM
s.skip::<i16>(); // font direction hint
let index_to_location_format = s.read::<u16>()?;
if !(16..=16384).contains(&units_per_em) {
return None;
}
let index_to_location_format = match index_to_location_format {
0 => IndexToLocationFormat::Short,
1 => IndexToLocationFormat::Long,
_ => return None,
};
Some(Table {
units_per_em,
global_bbox: Rect {
x_min,
y_min,
x_max,
y_max,
},
index_to_location_format,
})
}
}

43
vendor/ttf-parser/src/tables/hhea.rs vendored Normal file
View File

@@ -0,0 +1,43 @@
//! A [Horizontal Header Table](
//! https://docs.microsoft.com/en-us/typography/opentype/spec/hhea) implementation.
use crate::parser::Stream;
/// A [Horizontal Header Table](https://docs.microsoft.com/en-us/typography/opentype/spec/hhea).
#[derive(Clone, Copy, Debug)]
pub struct Table {
/// Face ascender.
pub ascender: i16,
/// Face descender.
pub descender: i16,
/// Face line gap.
pub line_gap: i16,
/// Number of metrics in the `hmtx` table.
pub number_of_metrics: u16,
}
impl Table {
/// Parses a table from raw data.
pub fn parse(data: &[u8]) -> Option<Self> {
// Do not check the exact length, because some fonts include
// padding in table's length in table records, which is incorrect.
if data.len() < 36 {
return None;
}
let mut s = Stream::new(data);
s.skip::<u32>(); // version
let ascender = s.read::<i16>()?;
let descender = s.read::<i16>()?;
let line_gap = s.read::<i16>()?;
s.advance(24);
let number_of_metrics = s.read::<u16>()?;
Some(Table {
ascender,
descender,
line_gap,
number_of_metrics,
})
}
}

114
vendor/ttf-parser/src/tables/hmtx.rs vendored Normal file
View File

@@ -0,0 +1,114 @@
//! A [Horizontal/Vertical Metrics Table](
//! https://docs.microsoft.com/en-us/typography/opentype/spec/hmtx) implementation.
use core::num::NonZeroU16;
use crate::parser::{FromData, LazyArray16, Stream};
use crate::GlyphId;
/// Horizontal/Vertical Metrics.
#[derive(Clone, Copy, Debug)]
pub struct Metrics {
/// Width/Height advance for `hmtx`/`vmtx`.
pub advance: u16,
/// Left/Top side bearing for `hmtx`/`vmtx`.
pub side_bearing: i16,
}
impl FromData for Metrics {
const SIZE: usize = 4;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(Metrics {
advance: s.read::<u16>()?,
side_bearing: s.read::<i16>()?,
})
}
}
/// A [Horizontal/Vertical Metrics Table](
/// https://docs.microsoft.com/en-us/typography/opentype/spec/hmtx).
///
/// `hmtx` and `vmtx` tables has the same structure, so we're reusing the same struct for both.
#[derive(Clone, Copy, Debug)]
pub struct Table<'a> {
/// A list of metrics indexed by glyph ID.
pub metrics: LazyArray16<'a, Metrics>,
/// Side bearings for glyph IDs greater than or equal to the number of `metrics` values.
pub bearings: LazyArray16<'a, i16>,
/// Sum of long metrics + bearings.
pub number_of_metrics: u16,
}
impl<'a> Table<'a> {
/// Parses a table from raw data.
///
/// - `number_of_metrics` is from the `hhea`/`vhea` table.
/// - `number_of_glyphs` is from the `maxp` table.
pub fn parse(
mut number_of_metrics: u16,
number_of_glyphs: NonZeroU16,
data: &'a [u8],
) -> Option<Self> {
if number_of_metrics == 0 {
return None;
}
let mut s = Stream::new(data);
let metrics = s.read_array16::<Metrics>(number_of_metrics)?;
// 'If the number_of_metrics is less than the total number of glyphs,
// then that array is followed by an array for the left side bearing values
// of the remaining glyphs.'
let bearings_count = number_of_glyphs.get().checked_sub(number_of_metrics);
let bearings = if let Some(count) = bearings_count {
number_of_metrics += count;
// Some malformed fonts can skip "left side bearing values"
// even when they are expected.
// Therefore if we weren't able to parser them, simply fallback to an empty array.
// No need to mark the whole table as malformed.
s.read_array16::<i16>(count).unwrap_or_default()
} else {
LazyArray16::default()
};
Some(Table {
metrics,
bearings,
number_of_metrics,
})
}
/// Returns advance for a glyph.
#[inline]
pub fn advance(&self, glyph_id: GlyphId) -> Option<u16> {
if glyph_id.0 >= self.number_of_metrics {
return None;
}
if let Some(metrics) = self.metrics.get(glyph_id.0) {
Some(metrics.advance)
} else {
// 'As an optimization, the number of records can be less than the number of glyphs,
// in which case the advance value of the last record applies
// to all remaining glyph IDs.'
self.metrics.last().map(|m| m.advance)
}
}
/// Returns side bearing for a glyph.
#[inline]
pub fn side_bearing(&self, glyph_id: GlyphId) -> Option<i16> {
if let Some(metrics) = self.metrics.get(glyph_id.0) {
Some(metrics.side_bearing)
} else {
// 'If the number_of_metrics is less than the total number of glyphs,
// then that array is followed by an array for the side bearing values
// of the remaining glyphs.'
self.bearings
.get(glyph_id.0.checked_sub(self.metrics.len())?)
}
}
}

80
vendor/ttf-parser/src/tables/hvar.rs vendored Normal file
View File

@@ -0,0 +1,80 @@
//! A [Horizontal/Vertical Metrics Variations Table](
//! https://docs.microsoft.com/en-us/typography/opentype/spec/hvar) implementation.
use crate::delta_set::DeltaSetIndexMap;
use crate::parser::{Offset, Offset32, Stream};
use crate::var_store::ItemVariationStore;
use crate::{GlyphId, NormalizedCoordinate};
/// A [Horizontal/Vertical Metrics Variations Table](
/// https://docs.microsoft.com/en-us/typography/opentype/spec/hvar).
#[derive(Clone, Copy)]
pub struct Table<'a> {
data: &'a [u8],
variation_store: ItemVariationStore<'a>,
advance_width_mapping_offset: Option<Offset32>,
lsb_mapping_offset: Option<Offset32>,
}
impl<'a> Table<'a> {
/// Parses a table from raw data.
pub fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let version = s.read::<u32>()?;
if version != 0x00010000 {
return None;
}
let variation_store_offset = s.read::<Offset32>()?;
let var_store_s = Stream::new_at(data, variation_store_offset.to_usize())?;
let variation_store = ItemVariationStore::parse(var_store_s)?;
Some(Table {
data,
variation_store,
advance_width_mapping_offset: s.read::<Option<Offset32>>()?,
lsb_mapping_offset: s.read::<Option<Offset32>>()?,
})
}
/// Returns advance offset for a glyph.
#[inline]
pub fn advance_offset(
&self,
glyph_id: GlyphId,
coordinates: &[NormalizedCoordinate],
) -> Option<f32> {
let (outer_idx, inner_idx) = if let Some(offset) = self.advance_width_mapping_offset {
DeltaSetIndexMap::new(self.data.get(offset.to_usize()..)?).map(glyph_id.0 as u32)?
} else {
// 'If there is no delta-set index mapping table for advance widths,
// then glyph IDs implicitly provide the indices:
// for a given glyph ID, the delta-set outer-level index is zero,
// and the glyph ID is the delta-set inner-level index.'
(0, glyph_id.0)
};
self.variation_store
.parse_delta(outer_idx, inner_idx, coordinates)
}
/// Returns side bearing offset for a glyph.
#[inline]
pub fn side_bearing_offset(
&self,
glyph_id: GlyphId,
coordinates: &[NormalizedCoordinate],
) -> Option<f32> {
let set_data = self.data.get(self.lsb_mapping_offset?.to_usize()..)?;
let (outer_idx, inner_idx) = DeltaSetIndexMap::new(set_data).map(glyph_id.0 as u32)?;
self.variation_store
.parse_delta(outer_idx, inner_idx, coordinates)
}
}
impl core::fmt::Debug for Table<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Table {{ ... }}")
}
}

468
vendor/ttf-parser/src/tables/kern.rs vendored Normal file
View File

@@ -0,0 +1,468 @@
/*!
A [Kerning Table](
https://docs.microsoft.com/en-us/typography/opentype/spec/kern) implementation.
Supports both
[OpenType](https://docs.microsoft.com/en-us/typography/opentype/spec/kern)
and
[Apple Advanced Typography](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kern.html)
variants.
Since there is no single correct way to process a kerning data,
we have to provide an access to kerning subtables, so a caller can implement
a kerning algorithm manually.
But we still try to keep the API as high-level as possible.
*/
#[cfg(feature = "apple-layout")]
use crate::aat;
use crate::parser::{FromData, LazyArray16, NumFrom, Offset, Offset16, Stream};
use crate::GlyphId;
#[derive(Clone, Copy, Debug)]
struct OTCoverage(u8);
#[rustfmt::skip]
impl OTCoverage {
#[inline] fn is_horizontal(self) -> bool { self.0 & (1 << 0) != 0 }
#[inline] fn has_cross_stream(self) -> bool { self.0 & (1 << 2) != 0 }
}
impl FromData for OTCoverage {
const SIZE: usize = 1;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
data.get(0).copied().map(OTCoverage)
}
}
#[derive(Clone, Copy, Debug)]
struct AATCoverage(u8);
#[rustfmt::skip]
impl AATCoverage {
#[inline] fn is_horizontal(self) -> bool { self.0 & (1 << 7) == 0 }
#[inline] fn has_cross_stream(self) -> bool { self.0 & (1 << 6) != 0 }
#[inline] fn is_variable(self) -> bool { self.0 & (1 << 5) != 0 }
}
impl FromData for AATCoverage {
const SIZE: usize = 1;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
data.get(0).copied().map(AATCoverage)
}
}
/// A kerning pair.
#[derive(Clone, Copy, Debug)]
pub struct KerningPair {
/// Glyphs pair.
///
/// In the kern table spec, a kerning pair is stored as two u16,
/// but we are using one u32, so we can binary search it directly.
pub pair: u32,
/// Kerning value.
pub value: i16,
}
impl KerningPair {
/// Returns left glyph ID.
#[inline]
pub fn left(&self) -> GlyphId {
GlyphId((self.pair >> 16) as u16)
}
/// Returns right glyph ID.
#[inline]
pub fn right(&self) -> GlyphId {
GlyphId(self.pair as u16)
}
}
impl FromData for KerningPair {
const SIZE: usize = 6;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(KerningPair {
pair: s.read::<u32>()?,
value: s.read::<i16>()?,
})
}
}
/// A kerning subtable format.
#[allow(missing_docs)]
#[derive(Clone, Debug)]
pub enum Format<'a> {
Format0(Subtable0<'a>),
#[cfg(feature = "apple-layout")]
Format1(aat::StateTable<'a>),
#[cfg(not(feature = "apple-layout"))]
Format1,
Format2(Subtable2<'a>),
Format3(Subtable3<'a>),
}
/// A kerning subtable.
#[derive(Clone, Debug)]
pub struct Subtable<'a> {
/// Indicates that subtable is for horizontal text.
pub horizontal: bool,
/// Indicates that subtable is variable.
pub variable: bool,
/// Indicates that subtable has a cross-stream values.
pub has_cross_stream: bool,
/// Indicates that subtable uses a state machine.
///
/// In this case `glyphs_kerning()` will return `None`.
pub has_state_machine: bool,
/// Subtable format.
pub format: Format<'a>,
}
impl<'a> Subtable<'a> {
/// Returns kerning for a pair of glyphs.
///
/// Returns `None` in case of state machine based subtable.
#[inline]
pub fn glyphs_kerning(&self, left: GlyphId, right: GlyphId) -> Option<i16> {
match self.format {
Format::Format0(ref subtable) => subtable.glyphs_kerning(left, right),
Format::Format2(ref subtable) => subtable.glyphs_kerning(left, right),
Format::Format3(ref subtable) => subtable.glyphs_kerning(left, right),
_ => None,
}
}
}
/// A list of subtables.
///
/// The internal data layout is not designed for random access,
/// therefore we're not providing the `get()` method and only an iterator.
#[derive(Clone, Copy)]
pub struct Subtables<'a> {
/// Indicates an Apple Advanced Typography format.
is_aat: bool,
/// The total number of tables.
count: u32,
/// Actual data. Starts right after the `kern` header.
data: &'a [u8],
}
impl<'a> Subtables<'a> {
/// Returns the number of subtables.
pub fn len(&self) -> u32 {
self.count
}
/// Checks if there are any subtables.
pub fn is_empty(&self) -> bool {
self.count == 0
}
}
impl core::fmt::Debug for Subtables<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Subtables {{ ... }}")
}
}
impl<'a> IntoIterator for Subtables<'a> {
type Item = Subtable<'a>;
type IntoIter = SubtablesIter<'a>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
SubtablesIter {
is_aat: self.is_aat,
table_index: 0,
number_of_tables: self.count,
stream: Stream::new(self.data),
}
}
}
/// An iterator over kerning subtables.
#[allow(missing_debug_implementations)]
#[derive(Clone, Default)]
pub struct SubtablesIter<'a> {
/// Indicates an Apple Advanced Typography format.
is_aat: bool,
/// The current table index,
table_index: u32,
/// The total number of tables.
number_of_tables: u32,
/// Actual data. Starts right after `kern` header.
stream: Stream<'a>,
}
impl<'a> Iterator for SubtablesIter<'a> {
type Item = Subtable<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.table_index == self.number_of_tables {
return None;
}
if self.stream.at_end() {
return None;
}
if self.is_aat {
const HEADER_SIZE: u8 = 8;
let table_len = self.stream.read::<u32>()?;
let coverage = self.stream.read::<AATCoverage>()?;
let format_id = self.stream.read::<u8>()?;
self.stream.skip::<u16>(); // variation tuple index
if format_id > 3 {
// Unknown format.
return None;
}
// Subtract the header size.
let data_len = usize::num_from(table_len).checked_sub(usize::from(HEADER_SIZE))?;
let data = self.stream.read_bytes(data_len)?;
let format = match format_id {
0 => Format::Format0(Subtable0::parse(data)?),
#[cfg(feature = "apple-layout")]
1 => Format::Format1(aat::StateTable::parse(data)?),
#[cfg(not(feature = "apple-layout"))]
1 => Format::Format1,
2 => Format::Format2(Subtable2::parse(HEADER_SIZE, data)?),
3 => Format::Format3(Subtable3::parse(data)?),
_ => return None,
};
Some(Subtable {
horizontal: coverage.is_horizontal(),
variable: coverage.is_variable(),
has_cross_stream: coverage.has_cross_stream(),
has_state_machine: format_id == 1,
format,
})
} else {
const HEADER_SIZE: u8 = 6;
self.stream.skip::<u16>(); // version
let table_len = self.stream.read::<u16>()?;
// In the OpenType variant, `format` comes first.
let format_id = self.stream.read::<u8>()?;
let coverage = self.stream.read::<OTCoverage>()?;
if format_id != 0 && format_id != 2 {
// Unknown format.
return None;
}
let data_len = if self.number_of_tables == 1 {
// An OpenType `kern` table with just one subtable is a special case.
// The `table_len` property is mainly required to jump to the next subtable,
// but if there is only one subtable, this property can be ignored.
// This is abused by some fonts, to get around the `u16` size limit.
self.stream.tail()?.len()
} else {
// Subtract the header size.
usize::from(table_len).checked_sub(usize::from(HEADER_SIZE))?
};
let data = self.stream.read_bytes(data_len)?;
let format = match format_id {
0 => Format::Format0(Subtable0::parse(data)?),
2 => Format::Format2(Subtable2::parse(HEADER_SIZE, data)?),
_ => return None,
};
Some(Subtable {
horizontal: coverage.is_horizontal(),
variable: false, // Only AAT supports it.
has_cross_stream: coverage.has_cross_stream(),
has_state_machine: format_id == 1,
format,
})
}
}
}
/// A format 0 subtable.
///
/// Ordered List of Kerning Pairs.
#[derive(Clone, Copy, Debug)]
pub struct Subtable0<'a> {
/// A list of kerning pairs.
pub pairs: LazyArray16<'a, KerningPair>,
}
impl<'a> Subtable0<'a> {
/// Parses a subtable from raw data.
pub fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let number_of_pairs = s.read::<u16>()?;
s.advance(6); // search_range (u16) + entry_selector (u16) + range_shift (u16)
let pairs = s.read_array16::<KerningPair>(number_of_pairs)?;
Some(Self { pairs })
}
/// Returns kerning for a pair of glyphs.
#[inline]
pub fn glyphs_kerning(&self, left: GlyphId, right: GlyphId) -> Option<i16> {
let needle = u32::from(left.0) << 16 | u32::from(right.0);
self.pairs
.binary_search_by(|v| v.pair.cmp(&needle))
.map(|(_, v)| v.value)
}
}
/// A format 2 subtable.
///
/// Simple n x m Array of Kerning Values.
#[derive(Clone, Copy, Debug)]
pub struct Subtable2<'a> {
// TODO: parse actual structure
data: &'a [u8],
header_len: u8,
}
impl<'a> Subtable2<'a> {
/// Parses a subtable from raw data.
pub fn parse(header_len: u8, data: &'a [u8]) -> Option<Self> {
Some(Self { header_len, data })
}
/// Returns kerning for a pair of glyphs.
pub fn glyphs_kerning(&self, left: GlyphId, right: GlyphId) -> Option<i16> {
let mut s = Stream::new(self.data);
s.skip::<u16>(); // row_width
// Offsets are from beginning of the subtable and not from the `data` start,
// so we have to subtract the header.
let header_len = usize::from(self.header_len);
let left_hand_table_offset = s.read::<Offset16>()?.to_usize().checked_sub(header_len)?;
let right_hand_table_offset = s.read::<Offset16>()?.to_usize().checked_sub(header_len)?;
let array_offset = s.read::<Offset16>()?.to_usize().checked_sub(header_len)?;
// 'The array can be indexed by completing the left-hand and right-hand class mappings,
// adding the class values to the address of the subtable,
// and fetching the kerning value to which the new address points.'
let left_class = get_format2_class(left.0, left_hand_table_offset, self.data).unwrap_or(0);
let right_class =
get_format2_class(right.0, right_hand_table_offset, self.data).unwrap_or(0);
// 'Values within the left-hand offset table should not be less than the kerning array offset.'
if usize::from(left_class) < array_offset {
return None;
}
// Classes are already premultiplied, so we only need to sum them.
let index = usize::from(left_class) + usize::from(right_class);
let value_offset = index.checked_sub(header_len)?;
Stream::read_at::<i16>(self.data, value_offset)
}
}
pub(crate) fn get_format2_class(glyph_id: u16, offset: usize, data: &[u8]) -> Option<u16> {
let mut s = Stream::new_at(data, offset)?;
let first_glyph = s.read::<u16>()?;
let index = glyph_id.checked_sub(first_glyph)?;
let number_of_classes = s.read::<u16>()?;
let classes = s.read_array16::<u16>(number_of_classes)?;
classes.get(index)
}
/// A format 3 subtable.
///
/// Simple n x m Array of Kerning Indices.
#[derive(Clone, Copy, Debug)]
pub struct Subtable3<'a> {
// TODO: parse actual structure
data: &'a [u8],
}
impl<'a> Subtable3<'a> {
/// Parses a subtable from raw data.
pub fn parse(data: &'a [u8]) -> Option<Self> {
Some(Self { data })
}
/// Returns kerning for a pair of glyphs.
#[inline]
pub fn glyphs_kerning(&self, left: GlyphId, right: GlyphId) -> Option<i16> {
let mut s = Stream::new(self.data);
let glyph_count = s.read::<u16>()?;
let kerning_values_count = s.read::<u8>()?;
let left_hand_classes_count = s.read::<u8>()?;
let right_hand_classes_count = s.read::<u8>()?;
s.skip::<u8>(); // reserved
let indices_count =
u16::from(left_hand_classes_count) * u16::from(right_hand_classes_count);
let kerning_values = s.read_array16::<i16>(u16::from(kerning_values_count))?;
let left_hand_classes = s.read_array16::<u8>(glyph_count)?;
let right_hand_classes = s.read_array16::<u8>(glyph_count)?;
let indices = s.read_array16::<u8>(indices_count)?;
let left_class = left_hand_classes.get(left.0)?;
let right_class = right_hand_classes.get(right.0)?;
if left_class > left_hand_classes_count || right_class > right_hand_classes_count {
return None;
}
let index =
u16::from(left_class) * u16::from(right_hand_classes_count) + u16::from(right_class);
let index = indices.get(index)?;
kerning_values.get(u16::from(index))
}
}
/// A [Kerning Table](https://docs.microsoft.com/en-us/typography/opentype/spec/kern).
#[derive(Clone, Copy, Debug)]
pub struct Table<'a> {
/// A list of subtables.
pub subtables: Subtables<'a>,
}
impl<'a> Table<'a> {
/// Parses a table from raw data.
pub fn parse(data: &'a [u8]) -> Option<Self> {
// The `kern` table has two variants: OpenType and Apple.
// And they both have different headers.
// There are no robust way to distinguish them, so we have to guess.
//
// The OpenType one has the first two bytes (UInt16) as a version set to 0.
// While Apple one has the first four bytes (Fixed) set to 1.0
// So the first two bytes in case of an OpenType format will be 0x0000
// and 0x0001 in case of an Apple format.
let mut s = Stream::new(data);
let version = s.read::<u16>()?;
let subtables = if version == 0 {
let count = s.read::<u16>()?;
Subtables {
is_aat: false,
count: u32::from(count),
data: s.tail()?,
}
} else {
s.skip::<u16>(); // Skip the second part of u32 version.
// Note that AAT stores the number of tables as u32 and not as u16.
let count = s.read::<u32>()?;
Subtables {
is_aat: true,
count,
data: s.tail()?,
}
};
Some(Self { subtables })
}
}

485
vendor/ttf-parser/src/tables/kerx.rs vendored Normal file
View File

@@ -0,0 +1,485 @@
//! An [Extended Kerning Table](
//! https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kerx.html) implementation.
// TODO: find a way to test this table
// This table is basically untested because it uses Apple's State Tables
// and I have no idea how to generate them.
use core::num::NonZeroU16;
use crate::kern::KerningPair;
use crate::parser::{FromData, LazyArray32, NumFrom, Offset, Offset32, Stream};
use crate::{aat, GlyphId};
const HEADER_SIZE: usize = 12;
/// A format 0 subtable.
///
/// Ordered List of Kerning Pairs.
///
/// The same as in `kern`, but uses `LazyArray32` instead of `LazyArray16`.
#[derive(Clone, Copy, Debug)]
pub struct Subtable0<'a> {
/// A list of kerning pairs.
pub pairs: LazyArray32<'a, KerningPair>,
}
impl<'a> Subtable0<'a> {
/// Parses a subtable from raw data.
fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let number_of_pairs = s.read::<u32>()?;
s.advance(12); // search_range (u32) + entry_selector (u32) + range_shift (u32)
let pairs = s.read_array32::<KerningPair>(number_of_pairs)?;
Some(Self { pairs })
}
/// Returns kerning for a pair of glyphs.
#[inline]
pub fn glyphs_kerning(&self, left: GlyphId, right: GlyphId) -> Option<i16> {
let needle = u32::from(left.0) << 16 | u32::from(right.0);
self.pairs
.binary_search_by(|v| v.pair.cmp(&needle))
.map(|(_, v)| v.value)
}
}
/// A state machine entry.
#[derive(Clone, Copy, Debug)]
pub struct EntryData {
/// An action index.
pub action_index: u16,
}
impl FromData for EntryData {
const SIZE: usize = 2;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(EntryData {
action_index: s.read::<u16>()?,
})
}
}
/// A format 1 subtable.
///
/// State Table for Contextual Kerning.
#[derive(Clone)]
pub struct Subtable1<'a> {
/// A state table.
pub state_table: aat::ExtendedStateTable<'a, EntryData>,
actions_data: &'a [u8],
}
impl<'a> Subtable1<'a> {
fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let state_table = aat::ExtendedStateTable::parse(number_of_glyphs, &mut s)?;
// Actions offset is right after the state table.
let actions_offset = s.read::<Offset32>()?;
// Actions offset is from the start of the state table and not from the start of subtable.
// And since we don't know the length of the actions data,
// simply store all the data after the offset.
let actions_data = data.get(actions_offset.to_usize()..)?;
Some(Subtable1 {
state_table,
actions_data,
})
}
/// Returns kerning at action index.
#[inline]
pub fn glyphs_kerning(&self, action_index: u16) -> Option<i16> {
Stream::read_at(self.actions_data, usize::from(action_index) * i16::SIZE)
}
}
impl<'a> core::ops::Deref for Subtable1<'a> {
type Target = aat::ExtendedStateTable<'a, EntryData>;
fn deref(&self) -> &Self::Target {
&self.state_table
}
}
impl core::fmt::Debug for Subtable1<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Subtable1 {{ ... }}")
}
}
/// A format 2 subtable.
///
/// Simple n x m Array of Kerning Values.
///
/// The same as in `kern`, but uses 32bit offsets instead of 16bit one.
#[derive(Clone, Copy)]
pub struct Subtable2<'a>(&'a [u8]); // TODO: parse actual structure
impl<'a> Subtable2<'a> {
/// Returns kerning for a pair of glyphs.
pub fn glyphs_kerning(&self, left: GlyphId, right: GlyphId) -> Option<i16> {
let mut s = Stream::new(self.0);
s.skip::<u32>(); // row_width
// Offsets are from beginning of the subtable and not from the `data` start,
// so we have to subtract the header.
let left_hand_table_offset = s.read::<Offset32>()?.to_usize().checked_sub(HEADER_SIZE)?;
let right_hand_table_offset = s.read::<Offset32>()?.to_usize().checked_sub(HEADER_SIZE)?;
let array_offset = s.read::<Offset32>()?.to_usize().checked_sub(HEADER_SIZE)?;
// 'The array can be indexed by completing the left-hand and right-hand class mappings,
// adding the class values to the address of the subtable,
// and fetching the kerning value to which the new address points.'
let left_class =
crate::kern::get_format2_class(left.0, left_hand_table_offset, self.0).unwrap_or(0);
let right_class =
crate::kern::get_format2_class(right.0, right_hand_table_offset, self.0).unwrap_or(0);
// 'Values within the left-hand offset table should not be less than the kerning array offset.'
if usize::from(left_class) < array_offset {
return None;
}
// Classes are already premultiplied, so we only need to sum them.
let index = usize::from(left_class) + usize::from(right_class);
let value_offset = index.checked_sub(HEADER_SIZE)?;
Stream::read_at::<i16>(self.0, value_offset)
}
}
impl core::fmt::Debug for Subtable2<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Subtable2 {{ ... }}")
}
}
/// A container of Anchor Points used by [`Subtable4`].
#[derive(Clone, Copy)]
pub struct AnchorPoints<'a>(&'a [u8]);
impl AnchorPoints<'_> {
/// Returns a mark and current anchor points at action index.
pub fn get(&self, action_index: u16) -> Option<(u16, u16)> {
let offset = usize::from(action_index) * u16::SIZE;
let mut s = Stream::new_at(self.0, offset)?;
Some((s.read::<u16>()?, s.read::<u16>()?))
}
}
impl core::fmt::Debug for AnchorPoints<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "AnchorPoints {{ ... }}")
}
}
/// A format 4 subtable.
///
/// State Table for Control Point/Anchor Point Positioning.
///
/// Note: I wasn't able to find any fonts that actually use
/// `ControlPointActions` and/or `ControlPointCoordinateActions`,
/// therefore only `AnchorPointActions` is supported.
#[derive(Clone)]
pub struct Subtable4<'a> {
/// A state table.
pub state_table: aat::ExtendedStateTable<'a, EntryData>,
/// Anchor points.
pub anchor_points: AnchorPoints<'a>,
}
impl<'a> Subtable4<'a> {
fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let state_table = aat::ExtendedStateTable::parse(number_of_glyphs, &mut s)?;
let flags = s.read::<u32>()?;
let action_type = ((flags & 0xC0000000) >> 30) as u8;
let points_offset = usize::num_from(flags & 0x00FFFFFF);
// We support only Anchor Point Actions.
if action_type != 1 {
return None;
}
Some(Self {
state_table,
anchor_points: AnchorPoints(data.get(points_offset..)?),
})
}
}
impl<'a> core::ops::Deref for Subtable4<'a> {
type Target = aat::ExtendedStateTable<'a, EntryData>;
fn deref(&self) -> &Self::Target {
&self.state_table
}
}
impl core::fmt::Debug for Subtable4<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Subtable4 {{ ... }}")
}
}
/// A format 6 subtable.
///
/// Simple Index-based n x m Array of Kerning Values.
#[derive(Clone, Copy)]
pub struct Subtable6<'a> {
data: &'a [u8],
number_of_glyphs: NonZeroU16,
}
impl<'a> Subtable6<'a> {
// TODO: parse actual structure
fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Self {
Subtable6 {
number_of_glyphs,
data,
}
}
/// Returns kerning for a pair of glyphs.
pub fn glyphs_kerning(&self, left: GlyphId, right: GlyphId) -> Option<i16> {
use core::convert::TryFrom;
let mut s = Stream::new(self.data);
let flags = s.read::<u32>()?;
s.skip::<u16>(); // row_count
s.skip::<u16>(); // col_count
// All offsets are from the start of the subtable.
let row_index_table_offset = s.read::<Offset32>()?.to_usize().checked_sub(HEADER_SIZE)?;
let column_index_table_offset =
s.read::<Offset32>()?.to_usize().checked_sub(HEADER_SIZE)?;
let kerning_array_offset = s.read::<Offset32>()?.to_usize().checked_sub(HEADER_SIZE)?;
let kerning_vector_offset = s.read::<Offset32>()?.to_usize().checked_sub(HEADER_SIZE)?;
let row_index_table_data = self.data.get(row_index_table_offset..)?;
let column_index_table_data = self.data.get(column_index_table_offset..)?;
let kerning_array_data = self.data.get(kerning_array_offset..)?;
let kerning_vector_data = self.data.get(kerning_vector_offset..)?;
let has_long_values = flags & 0x00000001 != 0;
if has_long_values {
let l: u32 = aat::Lookup::parse(self.number_of_glyphs, row_index_table_data)?
.value(left)
.unwrap_or(0) as u32;
let r: u32 = aat::Lookup::parse(self.number_of_glyphs, column_index_table_data)?
.value(right)
.unwrap_or(0) as u32;
let array_offset = usize::try_from(l + r).ok()?.checked_mul(i32::SIZE)?;
let vector_offset: u32 = Stream::read_at(kerning_array_data, array_offset)?;
Stream::read_at(kerning_vector_data, usize::num_from(vector_offset))
} else {
let l: u16 = aat::Lookup::parse(self.number_of_glyphs, row_index_table_data)?
.value(left)
.unwrap_or(0);
let r: u16 = aat::Lookup::parse(self.number_of_glyphs, column_index_table_data)?
.value(right)
.unwrap_or(0);
let array_offset = usize::try_from(l + r).ok()?.checked_mul(i16::SIZE)?;
let vector_offset: u16 = Stream::read_at(kerning_array_data, array_offset)?;
Stream::read_at(kerning_vector_data, usize::from(vector_offset))
}
}
}
impl core::fmt::Debug for Subtable6<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Subtable6 {{ ... }}")
}
}
/// An extended kerning subtable format.
#[allow(missing_docs)]
#[derive(Clone, Debug)]
pub enum Format<'a> {
Format0(Subtable0<'a>),
Format1(Subtable1<'a>),
Format2(Subtable2<'a>),
Format4(Subtable4<'a>),
Format6(Subtable6<'a>),
}
/// A kerning subtable.
#[derive(Clone, Debug)]
pub struct Subtable<'a> {
/// Indicates that subtable is for horizontal text.
pub horizontal: bool,
/// Indicates that subtable is variable.
pub variable: bool,
/// Indicates that subtable has a cross-stream values.
pub has_cross_stream: bool,
/// Indicates that subtable uses a state machine.
///
/// In this case `glyphs_kerning()` will return `None`.
pub has_state_machine: bool,
/// The tuple count.
///
/// This value is only used with variation fonts and should be 0 for all other fonts.
pub tuple_count: u32,
/// Subtable format.
pub format: Format<'a>,
}
impl<'a> Subtable<'a> {
/// Returns kerning for a pair of glyphs.
///
/// Returns `None` in case of state machine based subtable.
#[inline]
pub fn glyphs_kerning(&self, left: GlyphId, right: GlyphId) -> Option<i16> {
match self.format {
Format::Format0(ref subtable) => subtable.glyphs_kerning(left, right),
Format::Format1(_) => None,
Format::Format2(ref subtable) => subtable.glyphs_kerning(left, right),
Format::Format4(_) => None,
Format::Format6(ref subtable) => subtable.glyphs_kerning(left, right),
}
}
}
#[derive(Clone, Copy, Debug)]
struct Coverage(u8);
#[rustfmt::skip]
impl Coverage {
// TODO: use hex
#[inline] pub fn is_horizontal(self) -> bool { self.0 & (1 << 7) == 0 }
#[inline] pub fn has_cross_stream(self) -> bool { self.0 & (1 << 6) != 0 }
#[inline] pub fn is_variable(self) -> bool { self.0 & (1 << 5) != 0 }
}
/// A list of extended kerning subtables.
///
/// The internal data layout is not designed for random access,
/// therefore we're not providing the `get()` method and only an iterator.
#[derive(Clone, Copy)]
pub struct Subtables<'a> {
/// The number of glyphs from the `maxp` table.
number_of_glyphs: NonZeroU16,
/// The total number of tables.
number_of_tables: u32,
/// Actual data. Starts right after the `kerx` header.
data: &'a [u8],
}
impl core::fmt::Debug for Subtables<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Subtables {{ ... }}")
}
}
impl<'a> IntoIterator for Subtables<'a> {
type Item = Subtable<'a>;
type IntoIter = SubtablesIter<'a>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
SubtablesIter {
number_of_glyphs: self.number_of_glyphs,
table_index: 0,
number_of_tables: self.number_of_tables,
stream: Stream::new(self.data),
}
}
}
/// An iterator over extended kerning subtables.
#[allow(missing_debug_implementations)]
#[derive(Clone)]
pub struct SubtablesIter<'a> {
/// The number of glyphs from the `maxp` table.
number_of_glyphs: NonZeroU16,
/// The current table index.
table_index: u32,
/// The total number of tables.
number_of_tables: u32,
/// Actual data. Starts right after the `kerx` header.
stream: Stream<'a>,
}
impl<'a> Iterator for SubtablesIter<'a> {
type Item = Subtable<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.table_index == self.number_of_tables {
return None;
}
if self.stream.at_end() {
return None;
}
let s = &mut self.stream;
let table_len = s.read::<u32>()?;
let coverage = Coverage(s.read::<u8>()?);
s.skip::<u16>(); // unused
let raw_format = s.read::<u8>()?;
let tuple_count = s.read::<u32>()?;
// Subtract the header size.
let data_len = usize::num_from(table_len).checked_sub(HEADER_SIZE)?;
let data = s.read_bytes(data_len)?;
let format = match raw_format {
0 => Subtable0::parse(data).map(Format::Format0)?,
1 => Subtable1::parse(self.number_of_glyphs, data).map(Format::Format1)?,
2 => Format::Format2(Subtable2(data)),
4 => Subtable4::parse(self.number_of_glyphs, data).map(Format::Format4)?,
6 => Format::Format6(Subtable6::parse(self.number_of_glyphs, data)),
_ => {
// Unknown format.
return None;
}
};
Some(Subtable {
horizontal: coverage.is_horizontal(),
variable: coverage.is_variable(),
has_cross_stream: coverage.has_cross_stream(),
has_state_machine: raw_format == 1 || raw_format == 4,
tuple_count,
format,
})
}
}
/// An [Extended Kerning Table](
/// https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kerx.html).
#[derive(Clone, Copy, Debug)]
pub struct Table<'a> {
/// A list of subtables.
pub subtables: Subtables<'a>,
}
impl<'a> Table<'a> {
/// Parses a table from raw data.
///
/// `number_of_glyphs` is from the `maxp` table.
pub fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
s.skip::<u16>(); // version
s.skip::<u16>(); // padding
let number_of_tables = s.read::<u32>()?;
let subtables = Subtables {
number_of_glyphs,
number_of_tables,
data: s.tail()?,
};
Some(Table { subtables })
}
}

105
vendor/ttf-parser/src/tables/loca.rs vendored Normal file
View File

@@ -0,0 +1,105 @@
//! An [Index to Location Table](https://docs.microsoft.com/en-us/typography/opentype/spec/loca)
//! implementation.
use core::convert::TryFrom;
use core::num::NonZeroU16;
use core::ops::Range;
use crate::parser::{LazyArray16, NumFrom, Stream};
use crate::{GlyphId, IndexToLocationFormat};
/// An [Index to Location Table](https://docs.microsoft.com/en-us/typography/opentype/spec/loca).
#[derive(Clone, Copy, Debug)]
pub enum Table<'a> {
/// Short offsets.
Short(LazyArray16<'a, u16>),
/// Long offsets.
Long(LazyArray16<'a, u32>),
}
impl<'a> Table<'a> {
/// Parses a table from raw data.
///
/// - `number_of_glyphs` is from the `maxp` table.
/// - `format` is from the `head` table.
pub fn parse(
number_of_glyphs: NonZeroU16,
format: IndexToLocationFormat,
data: &'a [u8],
) -> Option<Self> {
// The number of ranges is `maxp.numGlyphs + 1`.
//
// Check for overflow first.
let mut total = if number_of_glyphs.get() == core::u16::MAX {
number_of_glyphs.get()
} else {
number_of_glyphs.get() + 1
};
// By the spec, the number of `loca` offsets is `maxp.numGlyphs + 1`.
// But some malformed fonts can have less glyphs than that.
// In which case we try to parse only the available offsets
// and do not return an error, since the expected data length
// would go beyond table's length.
//
// In case when `loca` has more data than needed we simply ignore the rest.
let actual_total = match format {
IndexToLocationFormat::Short => data.len() / 2,
IndexToLocationFormat::Long => data.len() / 4,
};
let actual_total = u16::try_from(actual_total).ok()?;
total = total.min(actual_total);
let mut s = Stream::new(data);
match format {
IndexToLocationFormat::Short => Some(Table::Short(s.read_array16::<u16>(total)?)),
IndexToLocationFormat::Long => Some(Table::Long(s.read_array16::<u32>(total)?)),
}
}
/// Returns the number of offsets.
#[inline]
pub fn len(&self) -> u16 {
match self {
Table::Short(ref array) => array.len(),
Table::Long(ref array) => array.len(),
}
}
/// Checks if there are any offsets.
pub fn is_empty(&self) -> bool {
self.len() == 0
}
/// Returns glyph's range in the `glyf` table.
#[inline]
pub fn glyph_range(&self, glyph_id: GlyphId) -> Option<Range<usize>> {
let glyph_id = glyph_id.0;
if glyph_id == core::u16::MAX {
return None;
}
// Glyph ID must be smaller than total number of values in a `loca` array.
if glyph_id + 1 >= self.len() {
return None;
}
let range = match self {
Table::Short(ref array) => {
// 'The actual local offset divided by 2 is stored.'
usize::from(array.get(glyph_id)?) * 2..usize::from(array.get(glyph_id + 1)?) * 2
}
Table::Long(ref array) => {
usize::num_from(array.get(glyph_id)?)..usize::num_from(array.get(glyph_id + 1)?)
}
};
if range.start >= range.end {
// 'The offsets must be in ascending order.'
// And range cannot be empty.
None
} else {
Some(range)
}
}
}

938
vendor/ttf-parser/src/tables/math.rs vendored Normal file
View File

@@ -0,0 +1,938 @@
//! A [Math Table](https://docs.microsoft.com/en-us/typography/opentype/spec/math) implementation.
use crate::gpos::Device;
use crate::opentype_layout::Coverage;
use crate::parser::{
FromData, FromSlice, LazyArray16, LazyOffsetArray16, Offset, Offset16, Stream,
};
use crate::GlyphId;
/// A [Math Value](https://docs.microsoft.com/en-us/typography/opentype/spec/math#mathvaluerecord)
/// with optional device corrections.
#[derive(Clone, Copy, Debug)]
pub struct MathValue<'a> {
/// The X or Y value in font design units.
pub value: i16,
/// Device corrections for this value.
pub device: Option<Device<'a>>,
}
impl<'a> MathValue<'a> {
fn parse(data: &'a [u8], parent: &'a [u8]) -> Option<Self> {
Some(MathValueRecord::parse(data)?.get(parent))
}
}
/// A math value record with unresolved offset.
#[derive(Clone, Copy)]
struct MathValueRecord {
value: i16,
device_offset: Option<Offset16>,
}
impl FromData for MathValueRecord {
const SIZE: usize = 4;
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
let value = s.read::<i16>()?;
let device_offset = s.read::<Option<Offset16>>()?;
Some(MathValueRecord {
value,
device_offset,
})
}
}
impl MathValueRecord {
fn get(self, data: &[u8]) -> MathValue {
let device = self
.device_offset
.and_then(|offset| data.get(offset.to_usize()..))
.and_then(Device::parse);
MathValue {
value: self.value,
device,
}
}
}
/// A mapping from glyphs to
/// [Math Values](https://docs.microsoft.com/en-us/typography/opentype/spec/math#mathvaluerecord).
#[derive(Clone, Copy)]
pub struct MathValues<'a> {
data: &'a [u8],
coverage: Coverage<'a>,
records: LazyArray16<'a, MathValueRecord>,
}
impl<'a> FromSlice<'a> for MathValues<'a> {
fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let coverage = s.parse_at_offset16::<Coverage>(data)?;
let count = s.read::<u16>()?;
let records = s.read_array16::<MathValueRecord>(count)?;
Some(MathValues {
data,
coverage,
records,
})
}
}
impl<'a> MathValues<'a> {
/// Returns the value for the glyph or `None` if it is not covered.
#[inline]
pub fn get(&self, glyph: GlyphId) -> Option<MathValue<'a>> {
let index = self.coverage.get(glyph)?;
Some(self.records.get(index)?.get(self.data))
}
}
impl core::fmt::Debug for MathValues<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "MathValues {{ ... }}")
}
}
/// A [Math Constants Table](https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathconstants-table).
#[derive(Clone, Copy)]
pub struct Constants<'a> {
data: &'a [u8],
}
impl<'a> FromSlice<'a> for Constants<'a> {
fn parse(data: &'a [u8]) -> Option<Self> {
Some(Constants { data })
}
}
impl core::fmt::Debug for Constants<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Constants {{ ... }}")
}
}
const SCRIPT_PERCENT_SCALE_DOWN_OFFSET: usize = 0;
const SCRIPT_SCRIPT_PERCENT_SCALE_DOWN_OFFSET: usize = 2;
const DELIMITED_SUB_FORMULA_MIN_HEIGHT_OFFSET: usize = 4;
const DISPLAY_OPERATOR_MIN_HEIGHT_OFFSET: usize = 6;
const MATH_LEADING_OFFSET: usize = 8;
const AXIS_HEIGHT_OFFSET: usize = 12;
const ACCENT_BASE_HEIGHT_OFFSET: usize = 16;
const FLATTENED_ACCENT_BASE_HEIGHT_OFFSET: usize = 20;
const SUBSCRIPT_SHIFT_DOWN_OFFSET: usize = 24;
const SUBSCRIPT_TOP_MAX_OFFSET: usize = 28;
const SUBSCRIPT_BASELINE_DROP_MIN_OFFSET: usize = 32;
const SUPERSCRIPT_SHIFT_UP_OFFSET: usize = 36;
const SUPERSCRIPT_SHIFT_UP_CRAMPED_OFFSET: usize = 40;
const SUPERSCRIPT_BOTTOM_MIN_OFFSET: usize = 44;
const SUPERSCRIPT_BASELINE_DROP_MAX_OFFSET: usize = 48;
const SUB_SUPERSCRIPT_GAP_MIN_OFFSET: usize = 52;
const SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT_OFFSET: usize = 56;
const SPACE_AFTER_SCRIPT_OFFSET: usize = 60;
const UPPER_LIMIT_GAP_MIN_OFFSET: usize = 64;
const UPPER_LIMIT_BASELINE_RISE_MIN_OFFSET: usize = 68;
const LOWER_LIMIT_GAP_MIN_OFFSET: usize = 72;
const LOWER_LIMIT_BASELINE_DROP_MIN_OFFSET: usize = 76;
const STACK_TOP_SHIFT_UP_OFFSET: usize = 80;
const STACK_TOP_DISPLAY_STYLE_SHIFT_UP_OFFSET: usize = 84;
const STACK_BOTTOM_SHIFT_DOWN_OFFSET: usize = 88;
const STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN_OFFSET: usize = 92;
const STACK_GAP_MIN_OFFSET: usize = 96;
const STACK_DISPLAY_STYLE_GAP_MIN_OFFSET: usize = 100;
const STRETCH_STACK_TOP_SHIFT_UP_OFFSET: usize = 104;
const STRETCH_STACK_BOTTOM_SHIFT_DOWN_OFFSET: usize = 108;
const STRETCH_STACK_GAP_ABOVE_MIN_OFFSET: usize = 112;
const STRETCH_STACK_GAP_BELOW_MIN_OFFSET: usize = 116;
const FRACTION_NUMERATOR_SHIFT_UP_OFFSET: usize = 120;
const FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP_OFFSET: usize = 124;
const FRACTION_DENOMINATOR_SHIFT_DOWN_OFFSET: usize = 128;
const FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN_OFFSET: usize = 132;
const FRACTION_NUMERATOR_GAP_MIN_OFFSET: usize = 136;
const FRACTION_NUM_DISPLAY_STYLE_GAP_MIN_OFFSET: usize = 140;
const FRACTION_RULE_THICKNESS_OFFSET: usize = 144;
const FRACTION_DENOMINATOR_GAP_MIN_OFFSET: usize = 148;
const FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN_OFFSET: usize = 152;
const SKEWED_FRACTION_HORIZONTAL_GAP_OFFSET: usize = 156;
const SKEWED_FRACTION_VERTICAL_GAP_OFFSET: usize = 160;
const OVERBAR_VERTICAL_GAP_OFFSET: usize = 164;
const OVERBAR_RULE_THICKNESS_OFFSET: usize = 168;
const OVERBAR_EXTRA_ASCENDER_OFFSET: usize = 172;
const UNDERBAR_VERTICAL_GAP_OFFSET: usize = 176;
const UNDERBAR_RULE_THICKNESS_OFFSET: usize = 180;
const UNDERBAR_EXTRA_DESCENDER_OFFSET: usize = 184;
const RADICAL_VERTICAL_GAP_OFFSET: usize = 188;
const RADICAL_DISPLAY_STYLE_VERTICAL_GAP_OFFSET: usize = 192;
const RADICAL_RULE_THICKNESS_OFFSET: usize = 196;
const RADICAL_EXTRA_ASCENDER_OFFSET: usize = 200;
const RADICAL_KERN_BEFORE_DEGREE_OFFSET: usize = 204;
const RADICAL_KERN_AFTER_DEGREE_OFFSET: usize = 208;
const RADICAL_DEGREE_BOTTOM_RAISE_PERCENT_OFFSET: usize = 212;
impl<'a> Constants<'a> {
/// Percentage of scaling down for level 1 superscripts and subscripts.
#[inline]
pub fn script_percent_scale_down(&self) -> i16 {
self.read_i16(SCRIPT_PERCENT_SCALE_DOWN_OFFSET)
}
/// Percentage of scaling down for level 2 (scriptScript) superscripts and subscripts.
#[inline]
pub fn script_script_percent_scale_down(&self) -> i16 {
self.read_i16(SCRIPT_SCRIPT_PERCENT_SCALE_DOWN_OFFSET)
}
/// Minimum height required for a delimited expression (contained within parentheses, etc.) to
/// be treated as a sub-formula.
#[inline]
pub fn delimited_sub_formula_min_height(&self) -> u16 {
self.read_u16(DELIMITED_SUB_FORMULA_MIN_HEIGHT_OFFSET)
}
/// Minimum height of n-ary operators (such as integral and summation) for formulas in display
/// mode (that is, appearing as standalone page elements, not embedded inline within text).
#[inline]
pub fn display_operator_min_height(&self) -> u16 {
self.read_u16(DISPLAY_OPERATOR_MIN_HEIGHT_OFFSET)
}
/// White space to be left between math formulas to ensure proper line spacing.
#[inline]
pub fn math_leading(&self) -> MathValue<'a> {
self.read_record(MATH_LEADING_OFFSET)
}
/// Axis height of the font.
#[inline]
pub fn axis_height(&self) -> MathValue<'a> {
self.read_record(AXIS_HEIGHT_OFFSET)
}
/// Maximum (ink) height of accent base that does not require raising the accents.
#[inline]
pub fn accent_base_height(&self) -> MathValue<'a> {
self.read_record(ACCENT_BASE_HEIGHT_OFFSET)
}
/// Maximum (ink) height of accent base that does not require flattening the accents.
#[inline]
pub fn flattened_accent_base_height(&self) -> MathValue<'a> {
self.read_record(FLATTENED_ACCENT_BASE_HEIGHT_OFFSET)
}
/// The standard shift down applied to subscript elements.
#[inline]
pub fn subscript_shift_down(&self) -> MathValue<'a> {
self.read_record(SUBSCRIPT_SHIFT_DOWN_OFFSET)
}
/// Maximum allowed height of the (ink) top of subscripts that does not require moving
/// subscripts further down.
#[inline]
pub fn subscript_top_max(&self) -> MathValue<'a> {
self.read_record(SUBSCRIPT_TOP_MAX_OFFSET)
}
/// Minimum allowed drop of the baseline of subscripts relative to the (ink) bottom of the
/// base.
#[inline]
pub fn subscript_baseline_drop_min(&self) -> MathValue<'a> {
self.read_record(SUBSCRIPT_BASELINE_DROP_MIN_OFFSET)
}
/// Standard shift up applied to superscript elements.
#[inline]
pub fn superscript_shift_up(&self) -> MathValue<'a> {
self.read_record(SUPERSCRIPT_SHIFT_UP_OFFSET)
}
/// Standard shift of superscripts relative to the base, in cramped style.
#[inline]
pub fn superscript_shift_up_cramped(&self) -> MathValue<'a> {
self.read_record(SUPERSCRIPT_SHIFT_UP_CRAMPED_OFFSET)
}
/// Minimum allowed height of the (ink) bottom of superscripts that does not require moving
/// subscripts further up.
#[inline]
pub fn superscript_bottom_min(&self) -> MathValue<'a> {
self.read_record(SUPERSCRIPT_BOTTOM_MIN_OFFSET)
}
/// Maximum allowed drop of the baseline of superscripts relative to the (ink) top of the
/// base.
#[inline]
pub fn superscript_baseline_drop_max(&self) -> MathValue<'a> {
self.read_record(SUPERSCRIPT_BASELINE_DROP_MAX_OFFSET)
}
/// Minimum gap between the superscript and subscript ink.
#[inline]
pub fn sub_superscript_gap_min(&self) -> MathValue<'a> {
self.read_record(SUB_SUPERSCRIPT_GAP_MIN_OFFSET)
}
/// The maximum level to which the (ink) bottom of superscript can be pushed to increase the
/// gap between superscript and subscript, before subscript starts being moved down.
#[inline]
pub fn superscript_bottom_max_with_subscript(&self) -> MathValue<'a> {
self.read_record(SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT_OFFSET)
}
/// Extra white space to be added after each subscript and superscript.
#[inline]
pub fn space_after_script(&self) -> MathValue<'a> {
self.read_record(SPACE_AFTER_SCRIPT_OFFSET)
}
/// Minimum gap between the (ink) bottom of the upper limit, and the (ink) top of the base
/// operator.
#[inline]
pub fn upper_limit_gap_min(&self) -> MathValue<'a> {
self.read_record(UPPER_LIMIT_GAP_MIN_OFFSET)
}
/// Minimum distance between baseline of upper limit and (ink) top of the base operator.
#[inline]
pub fn upper_limit_baseline_rise_min(&self) -> MathValue<'a> {
self.read_record(UPPER_LIMIT_BASELINE_RISE_MIN_OFFSET)
}
/// Minimum gap between (ink) top of the lower limit, and (ink) bottom of the base operator.
#[inline]
pub fn lower_limit_gap_min(&self) -> MathValue<'a> {
self.read_record(LOWER_LIMIT_GAP_MIN_OFFSET)
}
/// Minimum distance between baseline of the lower limit and (ink) bottom of the base operator.
#[inline]
pub fn lower_limit_baseline_drop_min(&self) -> MathValue<'a> {
self.read_record(LOWER_LIMIT_BASELINE_DROP_MIN_OFFSET)
}
/// Standard shift up applied to the top element of a stack.
#[inline]
pub fn stack_top_shift_up(&self) -> MathValue<'a> {
self.read_record(STACK_TOP_SHIFT_UP_OFFSET)
}
/// Standard shift up applied to the top element of a stack in display style.
#[inline]
pub fn stack_top_display_style_shift_up(&self) -> MathValue<'a> {
self.read_record(STACK_TOP_DISPLAY_STYLE_SHIFT_UP_OFFSET)
}
/// Standard shift down applied to the bottom element of a stack.
#[inline]
pub fn stack_bottom_shift_down(&self) -> MathValue<'a> {
self.read_record(STACK_BOTTOM_SHIFT_DOWN_OFFSET)
}
/// Standard shift down applied to the bottom element of a stack in display style.
#[inline]
pub fn stack_bottom_display_style_shift_down(&self) -> MathValue<'a> {
self.read_record(STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN_OFFSET)
}
/// Minimum gap between (ink) bottom of the top element of a stack, and the (ink) top of the
/// bottom element.
#[inline]
pub fn stack_gap_min(&self) -> MathValue<'a> {
self.read_record(STACK_GAP_MIN_OFFSET)
}
/// Minimum gap between (ink) bottom of the top element of a stack, and the (ink) top of the
/// bottom element in display style.
#[inline]
pub fn stack_display_style_gap_min(&self) -> MathValue<'a> {
self.read_record(STACK_DISPLAY_STYLE_GAP_MIN_OFFSET)
}
/// Standard shift up applied to the top element of the stretch stack.
#[inline]
pub fn stretch_stack_top_shift_up(&self) -> MathValue<'a> {
self.read_record(STRETCH_STACK_TOP_SHIFT_UP_OFFSET)
}
/// Standard shift down applied to the bottom element of the stretch stack.
#[inline]
pub fn stretch_stack_bottom_shift_down(&self) -> MathValue<'a> {
self.read_record(STRETCH_STACK_BOTTOM_SHIFT_DOWN_OFFSET)
}
/// Minimum gap between the ink of the stretched element, and the (ink) bottom of the element above.
#[inline]
pub fn stretch_stack_gap_above_min(&self) -> MathValue<'a> {
self.read_record(STRETCH_STACK_GAP_ABOVE_MIN_OFFSET)
}
/// Minimum gap between the ink of the stretched element, and the (ink) top of the element below.
#[inline]
pub fn stretch_stack_gap_below_min(&self) -> MathValue<'a> {
self.read_record(STRETCH_STACK_GAP_BELOW_MIN_OFFSET)
}
/// Standard shift up applied to the numerator.
#[inline]
pub fn fraction_numerator_shift_up(&self) -> MathValue<'a> {
self.read_record(FRACTION_NUMERATOR_SHIFT_UP_OFFSET)
}
/// Standard shift up applied to the numerator in display style.
#[inline]
pub fn fraction_numerator_display_style_shift_up(&self) -> MathValue<'a> {
self.read_record(FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP_OFFSET)
}
/// Standard shift down applied to the denominator.
#[inline]
pub fn fraction_denominator_shift_down(&self) -> MathValue<'a> {
self.read_record(FRACTION_DENOMINATOR_SHIFT_DOWN_OFFSET)
}
/// Standard shift down applied to the denominator in display style.
#[inline]
pub fn fraction_denominator_display_style_shift_down(&self) -> MathValue<'a> {
self.read_record(FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN_OFFSET)
}
/// Minimum tolerated gap between the (ink) bottom of the numerator and the ink of the
/// fraction bar.
#[inline]
pub fn fraction_numerator_gap_min(&self) -> MathValue<'a> {
self.read_record(FRACTION_NUMERATOR_GAP_MIN_OFFSET)
}
/// Minimum tolerated gap between the (ink) bottom of the numerator and the ink of the
/// fraction bar in display style.
#[inline]
pub fn fraction_num_display_style_gap_min(&self) -> MathValue<'a> {
self.read_record(FRACTION_NUM_DISPLAY_STYLE_GAP_MIN_OFFSET)
}
/// Thickness of the fraction bar.
#[inline]
pub fn fraction_rule_thickness(&self) -> MathValue<'a> {
self.read_record(FRACTION_RULE_THICKNESS_OFFSET)
}
/// Minimum tolerated gap between the (ink) top of the denominator and the ink of the fraction bar.
#[inline]
pub fn fraction_denominator_gap_min(&self) -> MathValue<'a> {
self.read_record(FRACTION_DENOMINATOR_GAP_MIN_OFFSET)
}
/// Minimum tolerated gap between the (ink) top of the denominator and the ink of the fraction
/// bar in display style.
#[inline]
pub fn fraction_denom_display_style_gap_min(&self) -> MathValue<'a> {
self.read_record(FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN_OFFSET)
}
/// Horizontal distance between the top and bottom elements of a skewed fraction.
#[inline]
pub fn skewed_fraction_horizontal_gap(&self) -> MathValue<'a> {
self.read_record(SKEWED_FRACTION_HORIZONTAL_GAP_OFFSET)
}
/// Vertical distance between the ink of the top and bottom elements of a skewed fraction.
#[inline]
pub fn skewed_fraction_vertical_gap(&self) -> MathValue<'a> {
self.read_record(SKEWED_FRACTION_VERTICAL_GAP_OFFSET)
}
/// Distance between the overbar and the (ink) top of he base.
#[inline]
pub fn overbar_vertical_gap(&self) -> MathValue<'a> {
self.read_record(OVERBAR_VERTICAL_GAP_OFFSET)
}
/// Thickness of overbar.
#[inline]
pub fn overbar_rule_thickness(&self) -> MathValue<'a> {
self.read_record(OVERBAR_RULE_THICKNESS_OFFSET)
}
/// Extra white space reserved above the overbar.
#[inline]
pub fn overbar_extra_ascender(&self) -> MathValue<'a> {
self.read_record(OVERBAR_EXTRA_ASCENDER_OFFSET)
}
/// Distance between underbar and (ink) bottom of the base.
#[inline]
pub fn underbar_vertical_gap(&self) -> MathValue<'a> {
self.read_record(UNDERBAR_VERTICAL_GAP_OFFSET)
}
/// Thickness of underbar.
#[inline]
pub fn underbar_rule_thickness(&self) -> MathValue<'a> {
self.read_record(UNDERBAR_RULE_THICKNESS_OFFSET)
}
/// Extra white space reserved below the underbar.
#[inline]
pub fn underbar_extra_descender(&self) -> MathValue<'a> {
self.read_record(UNDERBAR_EXTRA_DESCENDER_OFFSET)
}
/// Space between the (ink) top of the expression and the bar over it.
#[inline]
pub fn radical_vertical_gap(&self) -> MathValue<'a> {
self.read_record(RADICAL_VERTICAL_GAP_OFFSET)
}
/// Space between the (ink) top of the expression and the bar over it.
#[inline]
pub fn radical_display_style_vertical_gap(&self) -> MathValue<'a> {
self.read_record(RADICAL_DISPLAY_STYLE_VERTICAL_GAP_OFFSET)
}
/// Thickness of the radical rule.
#[inline]
pub fn radical_rule_thickness(&self) -> MathValue<'a> {
self.read_record(RADICAL_RULE_THICKNESS_OFFSET)
}
/// Extra white space reserved above the radical.
#[inline]
pub fn radical_extra_ascender(&self) -> MathValue<'a> {
self.read_record(RADICAL_EXTRA_ASCENDER_OFFSET)
}
/// Extra horizontal kern before the degree of a radical, if such is present.
#[inline]
pub fn radical_kern_before_degree(&self) -> MathValue<'a> {
self.read_record(RADICAL_KERN_BEFORE_DEGREE_OFFSET)
}
/// Negative kern after the degree of a radical, if such is present.
#[inline]
pub fn radical_kern_after_degree(&self) -> MathValue<'a> {
self.read_record(RADICAL_KERN_AFTER_DEGREE_OFFSET)
}
/// Height of the bottom of the radical degree, if such is present, in proportion to the
/// ascender of the radical sign.
#[inline]
pub fn radical_degree_bottom_raise_percent(&self) -> i16 {
self.read_i16(RADICAL_DEGREE_BOTTOM_RAISE_PERCENT_OFFSET)
}
/// Read an `i16` at an offset into the table.
#[inline]
fn read_i16(&self, offset: usize) -> i16 {
Stream::read_at(self.data, offset).unwrap_or(0)
}
/// Read an `u16` at an offset into the table.
#[inline]
fn read_u16(&self, offset: usize) -> u16 {
Stream::read_at(self.data, offset).unwrap_or(0)
}
/// Read a `MathValueRecord` at an offset into the table.
#[inline]
fn read_record(&self, offset: usize) -> MathValue<'a> {
self.data
.get(offset..)
.and_then(|data| MathValue::parse(data, self.data))
.unwrap_or(MathValue {
value: 0,
device: None,
})
}
}
/// A [Math Kern Table](https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathkern-table).
#[derive(Clone)]
pub struct Kern<'a> {
data: &'a [u8],
heights: LazyArray16<'a, MathValueRecord>,
kerns: LazyArray16<'a, MathValueRecord>,
}
impl<'a> Kern<'a> {
/// Number of heights at which the kern value changes.
pub fn count(&self) -> u16 {
self.heights.len()
}
/// The correction height at the given index.
///
/// The index must be smaller than `count()`.
pub fn height(&self, index: u16) -> Option<MathValue<'a>> {
Some(self.heights.get(index)?.get(self.data))
}
/// The kern value at the given index.
///
/// The index must be smaller than or equal to `count()`.
pub fn kern(&self, index: u16) -> Option<MathValue<'a>> {
Some(self.kerns.get(index)?.get(self.data))
}
}
impl<'a> FromSlice<'a> for Kern<'a> {
fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let count = s.read::<u16>()?;
let heights = s.read_array16::<MathValueRecord>(count)?;
let kerns = s.read_array16::<MathValueRecord>(count + 1)?;
Some(Kern {
data,
heights,
kerns,
})
}
}
impl core::fmt::Debug for Kern<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Kern {{ ... }}")
}
}
#[derive(Clone, Copy)]
struct KernInfoRecord {
top_right: Option<Offset16>,
top_left: Option<Offset16>,
bottom_right: Option<Offset16>,
bottom_left: Option<Offset16>,
}
impl FromData for KernInfoRecord {
const SIZE: usize = 8;
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(KernInfoRecord {
top_right: s.read::<Option<Offset16>>()?,
top_left: s.read::<Option<Offset16>>()?,
bottom_right: s.read::<Option<Offset16>>()?,
bottom_left: s.read::<Option<Offset16>>()?,
})
}
}
impl KernInfoRecord {
fn get<'a>(&self, data: &'a [u8]) -> KernInfo<'a> {
let parse_field = |offset: Option<Offset16>| {
offset
.and_then(|offset| data.get(offset.to_usize()..))
.and_then(Kern::parse)
};
KernInfo {
top_right: parse_field(self.top_right),
top_left: parse_field(self.top_left),
bottom_right: parse_field(self.bottom_right),
bottom_left: parse_field(self.bottom_left),
}
}
}
/// An [entry in a Math Kern Info Table](
/// https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathkerninforecord).
#[derive(Clone, Debug)]
pub struct KernInfo<'a> {
/// The kerning data for the top-right corner.
pub top_right: Option<Kern<'a>>,
/// The kerning data for the top-left corner.
pub top_left: Option<Kern<'a>>,
/// The kerning data for the bottom-right corner.
pub bottom_right: Option<Kern<'a>>,
/// The kerning data for the bottom-left corner.
pub bottom_left: Option<Kern<'a>>,
}
/// A [Math Kern Info Table](https://docs.microsoft.com/en-us/typography/opentype/spec/math#mathkerninfo-table).
#[derive(Clone, Copy)]
pub struct KernInfos<'a> {
data: &'a [u8],
coverage: Coverage<'a>,
records: LazyArray16<'a, KernInfoRecord>,
}
impl<'a> FromSlice<'a> for KernInfos<'a> {
fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let coverage = s.parse_at_offset16::<Coverage>(data)?;
let count = s.read::<u16>()?;
let records = s.read_array16::<KernInfoRecord>(count)?;
Some(KernInfos {
data,
coverage,
records,
})
}
}
impl<'a> KernInfos<'a> {
/// Returns the kerning info for the glyph or `None` if it is not covered.
#[inline]
pub fn get(&self, glyph: GlyphId) -> Option<KernInfo<'a>> {
let index = self.coverage.get(glyph)?;
Some(self.records.get(index)?.get(self.data))
}
}
impl core::fmt::Debug for KernInfos<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "KernInfos {{ ... }}")
}
}
/// A [Math Glyph Info Table](https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathglyphinfo-table).
#[derive(Clone, Copy, Debug)]
pub struct GlyphInfo<'a> {
/// Per-glyph italics correction values.
pub italic_corrections: Option<MathValues<'a>>,
/// Per-glyph horizontal positions for attaching mathematical accents.
pub top_accent_attachments: Option<MathValues<'a>>,
/// Glyphs which are _extended shapes_.
pub extended_shapes: Option<Coverage<'a>>,
/// Per-glyph information for mathematical kerning.
pub kern_infos: Option<KernInfos<'a>>,
}
impl<'a> FromSlice<'a> for GlyphInfo<'a> {
fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(GlyphInfo {
italic_corrections: s.parse_at_offset16::<MathValues>(data),
top_accent_attachments: s.parse_at_offset16::<MathValues>(data),
extended_shapes: s.parse_at_offset16::<Coverage>(data),
kern_infos: s.parse_at_offset16::<KernInfos>(data),
})
}
}
/// Glyph part flags.
#[derive(Clone, Copy, Debug)]
pub struct PartFlags(pub u16);
#[allow(missing_docs)]
impl PartFlags {
#[inline]
pub fn extender(self) -> bool {
self.0 & 0x0001 != 0
}
}
impl FromData for PartFlags {
const SIZE: usize = 2;
fn parse(data: &[u8]) -> Option<Self> {
u16::parse(data).map(PartFlags)
}
}
/// Details for a glyph part in an assembly.
#[derive(Clone, Copy, Debug)]
pub struct GlyphPart {
/// Glyph ID for the part.
pub glyph_id: GlyphId,
/// Lengths of the connectors on the start of the glyph, in font design units.
pub start_connector_length: u16,
/// Lengths of the connectors on the end of the glyph, in font design units.
pub end_connector_length: u16,
/// The full advance of the part, in font design units.
pub full_advance: u16,
/// Part flags.
pub part_flags: PartFlags,
}
impl FromData for GlyphPart {
const SIZE: usize = 10;
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(GlyphPart {
glyph_id: s.read::<GlyphId>()?,
start_connector_length: s.read::<u16>()?,
end_connector_length: s.read::<u16>()?,
full_advance: s.read::<u16>()?,
part_flags: s.read::<PartFlags>()?,
})
}
}
/// A [Glyph Assembly Table](https://learn.microsoft.com/en-us/typography/opentype/spec/math#glyphassembly-table).
#[derive(Clone, Copy, Debug)]
pub struct GlyphAssembly<'a> {
/// The italics correction of the assembled glyph.
pub italics_correction: MathValue<'a>,
/// Parts the assembly is composed of.
pub parts: LazyArray16<'a, GlyphPart>,
}
impl<'a> FromSlice<'a> for GlyphAssembly<'a> {
fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let italics_correction = s.read::<MathValueRecord>()?.get(data);
let count = s.read::<u16>()?;
let parts = s.read_array16::<GlyphPart>(count)?;
Some(GlyphAssembly {
italics_correction,
parts,
})
}
}
/// Description of math glyph variants.
#[derive(Clone, Copy, Debug)]
pub struct GlyphVariant {
/// The ID of the variant glyph.
pub variant_glyph: GlyphId,
/// Advance width/height, in design units, of the variant glyph.
pub advance_measurement: u16,
}
impl FromData for GlyphVariant {
const SIZE: usize = 4;
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(GlyphVariant {
variant_glyph: s.read::<GlyphId>()?,
advance_measurement: s.read::<u16>()?,
})
}
}
/// A [Math Glyph Construction Table](
/// https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathglyphconstruction-table).
#[derive(Clone, Copy, Debug)]
pub struct GlyphConstruction<'a> {
/// A general recipe on how to construct a variant with large advance width/height.
pub assembly: Option<GlyphAssembly<'a>>,
/// Prepared variants of the glyph with varying advances.
pub variants: LazyArray16<'a, GlyphVariant>,
}
impl<'a> FromSlice<'a> for GlyphConstruction<'a> {
fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let assembly = s.parse_at_offset16::<GlyphAssembly>(data);
let variant_count = s.read::<u16>()?;
let variants = s.read_array16::<GlyphVariant>(variant_count)?;
Some(GlyphConstruction { assembly, variants })
}
}
/// A mapping from glyphs to
/// [Math Glyph Construction Tables](
/// https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathglyphconstruction-table).
#[derive(Clone, Copy)]
pub struct GlyphConstructions<'a> {
coverage: Coverage<'a>,
constructions: LazyOffsetArray16<'a, GlyphConstruction<'a>>,
}
impl<'a> GlyphConstructions<'a> {
fn new(
data: &'a [u8],
coverage: Option<Coverage<'a>>,
offsets: LazyArray16<'a, Option<Offset16>>,
) -> Self {
GlyphConstructions {
coverage: coverage.unwrap_or(Coverage::Format1 {
glyphs: LazyArray16::new(&[]),
}),
constructions: LazyOffsetArray16::new(data, offsets),
}
}
/// Returns the construction for the glyph or `None` if it is not covered.
#[inline]
pub fn get(&self, glyph: GlyphId) -> Option<GlyphConstruction<'a>> {
let index = self.coverage.get(glyph)?;
self.constructions.get(index)
}
}
impl core::fmt::Debug for GlyphConstructions<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "GlyphConstructions {{ ... }}")
}
}
/// A [Math Variants Table](
/// https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathvariants-table).
#[derive(Clone, Copy, Debug)]
pub struct Variants<'a> {
/// Minimum overlap of connecting glyphs during glyph construction, in design units.
pub min_connector_overlap: u16,
/// Constructions for shapes growing in the vertical direction.
pub vertical_constructions: GlyphConstructions<'a>,
/// Constructions for shapes growing in the horizontal direction.
pub horizontal_constructions: GlyphConstructions<'a>,
}
impl<'a> FromSlice<'a> for Variants<'a> {
fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let min_connector_overlap = s.read::<u16>()?;
let vertical_coverage = s.parse_at_offset16::<Coverage>(data);
let horizontal_coverage = s.parse_at_offset16::<Coverage>(data);
let vertical_count = s.read::<u16>()?;
let horizontal_count = s.read::<u16>()?;
let vertical_offsets = s.read_array16::<Option<Offset16>>(vertical_count)?;
let horizontal_offsets = s.read_array16::<Option<Offset16>>(horizontal_count)?;
Some(Variants {
min_connector_overlap,
vertical_constructions: GlyphConstructions::new(
data,
vertical_coverage,
vertical_offsets,
),
horizontal_constructions: GlyphConstructions::new(
data,
horizontal_coverage,
horizontal_offsets,
),
})
}
}
/// A [Math Table](https://docs.microsoft.com/en-us/typography/opentype/spec/math).
#[derive(Clone, Copy, Debug)]
pub struct Table<'a> {
/// Math positioning constants.
pub constants: Option<Constants<'a>>,
/// Per-glyph positioning information.
pub glyph_info: Option<GlyphInfo<'a>>,
/// Variants and assembly recipes for growable glyphs.
pub variants: Option<Variants<'a>>,
}
impl<'a> Table<'a> {
/// Parses a table from raw data.
pub fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let major_version = s.read::<u16>()? as u8;
s.skip::<u16>(); // minor version
if major_version != 1 {
return None;
}
Some(Table {
constants: s.parse_at_offset16::<Constants>(data),
glyph_info: s.parse_at_offset16::<GlyphInfo>(data),
variants: s.parse_at_offset16::<Variants>(data),
})
}
}
trait StreamExt<'a> {
fn parse_at_offset16<T: FromSlice<'a>>(&mut self, data: &'a [u8]) -> Option<T>;
}
impl<'a> StreamExt<'a> for Stream<'a> {
fn parse_at_offset16<T: FromSlice<'a>>(&mut self, data: &'a [u8]) -> Option<T> {
let offset = self.read::<Option<Offset16>>()??.to_usize();
data.get(offset..).and_then(T::parse)
}
}

28
vendor/ttf-parser/src/tables/maxp.rs vendored Normal file
View File

@@ -0,0 +1,28 @@
//! A [Maximum Profile Table](
//! https://docs.microsoft.com/en-us/typography/opentype/spec/maxp) implementation.
use core::num::NonZeroU16;
use crate::parser::Stream;
/// A [Maximum Profile Table](https://docs.microsoft.com/en-us/typography/opentype/spec/maxp).
#[derive(Clone, Copy, Debug)]
pub struct Table {
/// The total number of glyphs in the face.
pub number_of_glyphs: NonZeroU16,
}
impl Table {
/// Parses a table from raw data.
pub fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
let version = s.read::<u32>()?;
if !(version == 0x00005000 || version == 0x00010000) {
return None;
}
let n = s.read::<u16>()?;
let number_of_glyphs = NonZeroU16::new(n)?;
Some(Table { number_of_glyphs })
}
}

56
vendor/ttf-parser/src/tables/mod.rs vendored Normal file
View File

@@ -0,0 +1,56 @@
pub mod cbdt;
pub mod cblc;
mod cff;
pub mod cmap;
pub mod colr;
pub mod cpal;
pub mod glyf;
pub mod head;
pub mod hhea;
pub mod hmtx;
pub mod kern;
pub mod loca;
pub mod maxp;
pub mod name;
pub mod os2;
pub mod post;
pub mod sbix;
pub mod svg;
pub mod vhea;
pub mod vorg;
#[cfg(feature = "opentype-layout")]
pub mod gdef;
#[cfg(feature = "opentype-layout")]
pub mod gpos;
#[cfg(feature = "opentype-layout")]
pub mod gsub;
#[cfg(feature = "opentype-layout")]
pub mod math;
#[cfg(feature = "apple-layout")]
pub mod ankr;
#[cfg(feature = "apple-layout")]
pub mod feat;
#[cfg(feature = "apple-layout")]
pub mod kerx;
#[cfg(feature = "apple-layout")]
pub mod morx;
#[cfg(feature = "apple-layout")]
pub mod trak;
#[cfg(feature = "variable-fonts")]
pub mod avar;
#[cfg(feature = "variable-fonts")]
pub mod fvar;
#[cfg(feature = "variable-fonts")]
pub mod gvar;
#[cfg(feature = "variable-fonts")]
pub mod hvar;
#[cfg(feature = "variable-fonts")]
pub mod mvar;
pub use cff::cff1;
#[cfg(feature = "variable-fonts")]
pub use cff::cff2;
pub use cff::CFFError;

470
vendor/ttf-parser/src/tables/morx.rs vendored Normal file
View File

@@ -0,0 +1,470 @@
//! An [Extended Glyph Metamorphosis Table](
//! https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6morx.html) implementation.
// Note: We do not have tests for this table because it has a very complicated structure.
// Specifically, the State Machine Tables. I have no idea how to generate them.
// And all fonts that use this table are mainly Apple one, so we cannot use them for legal reasons.
//
// On the other hand, this table is tested indirectly by https://github.com/RazrFalcon/rustybuzz
// And it has like 170 tests. Which is pretty good.
// Therefore after applying any changes to this table,
// you have to check that all rustybuzz tests are still passing.
use core::num::NonZeroU16;
use crate::parser::{FromData, LazyArray32, NumFrom, Offset, Offset32, Stream};
use crate::{aat, GlyphId};
/// The feature table is used to compute the sub-feature flags
/// for a list of requested features and settings.
#[derive(Clone, Copy, Debug)]
pub struct Feature {
/// The type of feature.
pub kind: u16,
/// The feature's setting (aka selector).
pub setting: u16,
/// Flags for the settings that this feature and setting enables.
pub enable_flags: u32,
/// Complement of flags for the settings that this feature and setting disable.
pub disable_flags: u32,
}
impl FromData for Feature {
const SIZE: usize = 12;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(Feature {
kind: s.read::<u16>()?,
setting: s.read::<u16>()?,
enable_flags: s.read::<u32>()?,
disable_flags: s.read::<u32>()?,
})
}
}
/// A contextual subtable state table trailing data.
#[derive(Clone, Copy, Debug)]
pub struct ContextualEntryData {
/// A mark index.
pub mark_index: u16,
/// A current index.
pub current_index: u16,
}
impl FromData for ContextualEntryData {
const SIZE: usize = 4;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(ContextualEntryData {
mark_index: s.read::<u16>()?,
current_index: s.read::<u16>()?,
})
}
}
/// A contextual subtable.
#[derive(Clone)]
pub struct ContextualSubtable<'a> {
/// The contextual glyph substitution state table.
pub state: aat::ExtendedStateTable<'a, ContextualEntryData>,
offsets_data: &'a [u8],
offsets: LazyArray32<'a, Offset32>,
number_of_glyphs: NonZeroU16,
}
impl<'a> ContextualSubtable<'a> {
fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let state = aat::ExtendedStateTable::parse(number_of_glyphs, &mut s)?;
// While the spec clearly states that this is an
// 'offset from the beginning of the state subtable',
// it's actually not. Subtable header should not be included.
let offset = s.read::<Offset32>()?.to_usize();
// The offsets list is unsized.
let offsets_data = data.get(offset..)?;
let offsets = LazyArray32::<Offset32>::new(offsets_data);
Some(ContextualSubtable {
state,
offsets_data,
offsets,
number_of_glyphs,
})
}
/// Returns a [Lookup](aat::Lookup) at index.
pub fn lookup(&self, index: u32) -> Option<aat::Lookup<'a>> {
let offset = self.offsets.get(index)?.to_usize();
let lookup_data = self.offsets_data.get(offset..)?;
aat::Lookup::parse(self.number_of_glyphs, lookup_data)
}
}
impl core::fmt::Debug for ContextualSubtable<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "ContextualSubtable {{ ... }}")
}
}
/// A ligature subtable.
#[derive(Clone, Debug)]
pub struct LigatureSubtable<'a> {
/// A state table.
pub state: aat::ExtendedStateTable<'a, u16>,
/// Ligature actions.
pub ligature_actions: LazyArray32<'a, u32>,
/// Ligature components.
pub components: LazyArray32<'a, u16>,
/// Ligatures.
pub ligatures: LazyArray32<'a, GlyphId>,
}
impl<'a> LigatureSubtable<'a> {
fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let state = aat::ExtendedStateTable::parse(number_of_glyphs, &mut s)?;
// Offset are from `ExtendedStateTable`/`data`, not from subtable start.
let ligature_action_offset = s.read::<Offset32>()?.to_usize();
let component_offset = s.read::<Offset32>()?.to_usize();
let ligature_offset = s.read::<Offset32>()?.to_usize();
// All three arrays are unsized, so we're simply reading/mapping all the data past offset.
let ligature_actions = LazyArray32::<u32>::new(data.get(ligature_action_offset..)?);
let components = LazyArray32::<u16>::new(data.get(component_offset..)?);
let ligatures = LazyArray32::<GlyphId>::new(data.get(ligature_offset..)?);
Some(LigatureSubtable {
state,
ligature_actions,
components,
ligatures,
})
}
}
/// A contextual subtable state table trailing data.
#[derive(Clone, Copy, Debug)]
pub struct InsertionEntryData {
/// A current insert index.
pub current_insert_index: u16,
/// A marked insert index.
pub marked_insert_index: u16,
}
impl FromData for InsertionEntryData {
const SIZE: usize = 4;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(InsertionEntryData {
current_insert_index: s.read::<u16>()?,
marked_insert_index: s.read::<u16>()?,
})
}
}
/// An insertion subtable.
#[derive(Clone, Debug)]
pub struct InsertionSubtable<'a> {
/// A state table.
pub state: aat::ExtendedStateTable<'a, InsertionEntryData>,
/// Insertion glyphs.
pub glyphs: LazyArray32<'a, GlyphId>,
}
impl<'a> InsertionSubtable<'a> {
fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let state = aat::ExtendedStateTable::parse(number_of_glyphs, &mut s)?;
let offset = s.read::<Offset32>()?.to_usize();
// TODO: unsized array?
// The list is unsized.
let glyphs = LazyArray32::<GlyphId>::new(data.get(offset..)?);
Some(InsertionSubtable { state, glyphs })
}
}
/// A subtable kind.
#[allow(missing_docs)]
#[derive(Clone, Debug)]
pub enum SubtableKind<'a> {
Rearrangement(aat::ExtendedStateTable<'a, ()>),
Contextual(ContextualSubtable<'a>),
Ligature(LigatureSubtable<'a>),
NonContextual(aat::Lookup<'a>),
Insertion(InsertionSubtable<'a>),
}
/// A subtable coverage.
#[derive(Clone, Copy, Debug)]
pub struct Coverage(u8);
#[rustfmt::skip]
impl Coverage {
/// If true, this subtable will process glyphs in logical order
/// (or reverse logical order if [`is_vertical`](Self::is_vertical) is also true).
#[inline] pub fn is_logical(self) -> bool { self.0 & 0x10 != 0 }
/// If true, this subtable will be applied to both horizontal and vertical text
/// ([`is_vertical`](Self::is_vertical) should be ignored).
#[inline] pub fn is_all_directions(self) -> bool { self.0 & 0x20 != 0 }
/// If true, this subtable will process glyphs in descending order.
#[inline] pub fn is_backwards(self) -> bool { self.0 & 0x40 != 0 }
/// If true, this subtable will only be applied to vertical text.
#[inline] pub fn is_vertical(self) -> bool { self.0 & 0x80 != 0 }
}
/// A subtable in a metamorphosis chain.
#[derive(Clone, Debug)]
pub struct Subtable<'a> {
/// A subtable kind.
pub kind: SubtableKind<'a>,
/// A subtable coverage.
pub coverage: Coverage,
/// Subtable feature flags.
pub feature_flags: u32,
}
/// A list of subtables in a metamorphosis chain.
///
/// The internal data layout is not designed for random access,
/// therefore we're not providing the `get()` method and only an iterator.
#[derive(Clone, Copy)]
pub struct Subtables<'a> {
count: u32,
data: &'a [u8],
number_of_glyphs: NonZeroU16,
}
impl<'a> IntoIterator for Subtables<'a> {
type Item = Subtable<'a>;
type IntoIter = SubtablesIter<'a>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
SubtablesIter {
index: 0,
count: self.count,
stream: Stream::new(self.data),
number_of_glyphs: self.number_of_glyphs,
}
}
}
impl core::fmt::Debug for Subtables<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Subtables {{ ... }}")
}
}
/// An iterator over a metamorphosis chain subtables.
#[allow(missing_debug_implementations)]
#[derive(Clone)]
pub struct SubtablesIter<'a> {
index: u32,
count: u32,
stream: Stream<'a>,
number_of_glyphs: NonZeroU16,
}
impl<'a> Iterator for SubtablesIter<'a> {
type Item = Subtable<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.index == self.count {
return None;
}
let s = &mut self.stream;
if s.at_end() {
return None;
}
let len = s.read::<u32>()?;
let coverage = Coverage(s.read::<u8>()?);
s.skip::<u16>(); // reserved
let kind = s.read::<u8>()?;
let feature_flags = s.read::<u32>()?;
const HEADER_LEN: usize = 12;
let len = usize::num_from(len).checked_sub(HEADER_LEN)?;
let subtables_data = s.read_bytes(len)?;
let kind = match kind {
0 => {
let mut s = Stream::new(subtables_data);
let table = aat::ExtendedStateTable::parse(self.number_of_glyphs, &mut s)?;
SubtableKind::Rearrangement(table)
}
1 => {
let table = ContextualSubtable::parse(self.number_of_glyphs, subtables_data)?;
SubtableKind::Contextual(table)
}
2 => {
let table = LigatureSubtable::parse(self.number_of_glyphs, subtables_data)?;
SubtableKind::Ligature(table)
}
// 3 - reserved
4 => SubtableKind::NonContextual(aat::Lookup::parse(
self.number_of_glyphs,
subtables_data,
)?),
5 => {
let table = InsertionSubtable::parse(self.number_of_glyphs, subtables_data)?;
SubtableKind::Insertion(table)
}
_ => return None,
};
Some(Subtable {
kind,
coverage,
feature_flags,
})
}
}
/// A metamorphosis chain.
#[derive(Clone, Copy, Debug)]
pub struct Chain<'a> {
/// Default chain features.
pub default_flags: u32,
/// A list of chain features.
pub features: LazyArray32<'a, Feature>,
/// A list of chain subtables.
pub subtables: Subtables<'a>,
}
/// A list of metamorphosis chains.
///
/// The internal data layout is not designed for random access,
/// therefore we're not providing the `get()` method and only an iterator.
#[derive(Clone, Copy)]
pub struct Chains<'a> {
data: &'a [u8],
count: u32,
number_of_glyphs: NonZeroU16,
}
impl<'a> Chains<'a> {
fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
s.skip::<u16>(); // version
s.skip::<u16>(); // reserved
let count = s.read::<u32>()?;
Some(Chains {
count,
data: s.tail()?,
number_of_glyphs,
})
}
}
impl<'a> IntoIterator for Chains<'a> {
type Item = Chain<'a>;
type IntoIter = ChainsIter<'a>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
ChainsIter {
index: 0,
count: self.count,
stream: Stream::new(self.data),
number_of_glyphs: self.number_of_glyphs,
}
}
}
impl core::fmt::Debug for Chains<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Chains {{ ... }}")
}
}
/// An iterator over metamorphosis chains.
#[allow(missing_debug_implementations)]
#[derive(Clone)]
pub struct ChainsIter<'a> {
index: u32,
count: u32,
stream: Stream<'a>,
number_of_glyphs: NonZeroU16,
}
impl<'a> Iterator for ChainsIter<'a> {
type Item = Chain<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.index == self.count {
return None;
}
if self.stream.at_end() {
return None;
}
let default_flags = self.stream.read::<u32>()?;
let len = self.stream.read::<u32>()?;
let features_count = self.stream.read::<u32>()?;
let subtables_count = self.stream.read::<u32>()?;
let features = self.stream.read_array32::<Feature>(features_count)?;
const HEADER_LEN: usize = 16;
let len = usize::num_from(len)
.checked_sub(HEADER_LEN)?
.checked_sub(Feature::SIZE * usize::num_from(features_count))?;
let subtables_data = self.stream.read_bytes(len)?;
let subtables = Subtables {
data: subtables_data,
count: subtables_count,
number_of_glyphs: self.number_of_glyphs,
};
Some(Chain {
default_flags,
features,
subtables,
})
}
}
/// An [Extended Glyph Metamorphosis Table](
/// https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6morx.html).
///
/// Subtable Glyph Coverage used by morx v3 is not supported.
#[derive(Clone)]
pub struct Table<'a> {
/// A list of metamorphosis chains.
pub chains: Chains<'a>,
}
impl core::fmt::Debug for Table<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Table {{ ... }}")
}
}
impl<'a> Table<'a> {
/// Parses a table from raw data.
///
/// `number_of_glyphs` is from the `maxp` table.
pub fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Option<Self> {
Chains::parse(number_of_glyphs, data).map(|chains| Self { chains })
}
}

84
vendor/ttf-parser/src/tables/mvar.rs vendored Normal file
View File

@@ -0,0 +1,84 @@
//! A [Metrics Variations Table](
//! https://docs.microsoft.com/en-us/typography/opentype/spec/mvar) implementation.
use crate::parser::{FromData, LazyArray16, Offset, Offset16, Stream};
use crate::var_store::ItemVariationStore;
use crate::{NormalizedCoordinate, Tag};
#[derive(Clone, Copy)]
struct ValueRecord {
value_tag: Tag,
delta_set_outer_index: u16,
delta_set_inner_index: u16,
}
impl FromData for ValueRecord {
const SIZE: usize = 8;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(ValueRecord {
value_tag: s.read::<Tag>()?,
delta_set_outer_index: s.read::<u16>()?,
delta_set_inner_index: s.read::<u16>()?,
})
}
}
/// A [Metrics Variations Table](
/// https://docs.microsoft.com/en-us/typography/opentype/spec/mvar).
#[derive(Clone, Copy)]
pub struct Table<'a> {
variation_store: ItemVariationStore<'a>,
records: LazyArray16<'a, ValueRecord>,
}
impl<'a> Table<'a> {
/// Parses a table from raw data.
pub fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let version = s.read::<u32>()?;
if version != 0x00010000 {
return None;
}
s.skip::<u16>(); // reserved
let value_record_size = s.read::<u16>()?;
if usize::from(value_record_size) != ValueRecord::SIZE {
return None;
}
let count = s.read::<u16>()?;
if count == 0 {
return None;
}
let var_store_offset = s.read::<Option<Offset16>>()??.to_usize();
let records = s.read_array16::<ValueRecord>(count)?;
let variation_store = ItemVariationStore::parse(Stream::new_at(data, var_store_offset)?)?;
Some(Table {
variation_store,
records,
})
}
/// Returns a metric offset by tag.
pub fn metric_offset(&self, tag: Tag, coordinates: &[NormalizedCoordinate]) -> Option<f32> {
let (_, record) = self.records.binary_search_by(|r| r.value_tag.cmp(&tag))?;
self.variation_store.parse_delta(
record.delta_set_outer_index,
record.delta_set_inner_index,
coordinates,
)
}
}
impl core::fmt::Debug for Table<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Table {{ ... }}")
}
}

335
vendor/ttf-parser/src/tables/name.rs vendored Normal file
View File

@@ -0,0 +1,335 @@
//! A [Naming Table](
//! https://docs.microsoft.com/en-us/typography/opentype/spec/name) implementation.
#[cfg(feature = "std")]
use std::string::String;
#[cfg(feature = "std")]
use std::vec::Vec;
use crate::parser::{FromData, LazyArray16, Offset, Offset16, Stream};
use crate::Language;
/// A list of [name ID](https://docs.microsoft.com/en-us/typography/opentype/spec/name#name-ids)'s.
pub mod name_id {
#![allow(missing_docs)]
pub const COPYRIGHT_NOTICE: u16 = 0;
pub const FAMILY: u16 = 1;
pub const SUBFAMILY: u16 = 2;
pub const UNIQUE_ID: u16 = 3;
pub const FULL_NAME: u16 = 4;
pub const VERSION: u16 = 5;
pub const POST_SCRIPT_NAME: u16 = 6;
pub const TRADEMARK: u16 = 7;
pub const MANUFACTURER: u16 = 8;
pub const DESIGNER: u16 = 9;
pub const DESCRIPTION: u16 = 10;
pub const VENDOR_URL: u16 = 11;
pub const DESIGNER_URL: u16 = 12;
pub const LICENSE: u16 = 13;
pub const LICENSE_URL: u16 = 14;
// RESERVED = 15
pub const TYPOGRAPHIC_FAMILY: u16 = 16;
pub const TYPOGRAPHIC_SUBFAMILY: u16 = 17;
pub const COMPATIBLE_FULL: u16 = 18;
pub const SAMPLE_TEXT: u16 = 19;
pub const POST_SCRIPT_CID: u16 = 20;
pub const WWS_FAMILY: u16 = 21;
pub const WWS_SUBFAMILY: u16 = 22;
pub const LIGHT_BACKGROUND_PALETTE: u16 = 23;
pub const DARK_BACKGROUND_PALETTE: u16 = 24;
pub const VARIATIONS_POST_SCRIPT_NAME_PREFIX: u16 = 25;
}
/// A [platform ID](https://docs.microsoft.com/en-us/typography/opentype/spec/name#platform-ids).
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum PlatformId {
Unicode,
Macintosh,
Iso,
Windows,
Custom,
}
impl FromData for PlatformId {
const SIZE: usize = 2;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
match u16::parse(data)? {
0 => Some(PlatformId::Unicode),
1 => Some(PlatformId::Macintosh),
2 => Some(PlatformId::Iso),
3 => Some(PlatformId::Windows),
4 => Some(PlatformId::Custom),
_ => None,
}
}
}
#[inline]
fn is_unicode_encoding(platform_id: PlatformId, encoding_id: u16) -> bool {
// https://docs.microsoft.com/en-us/typography/opentype/spec/name#windows-encoding-ids
const WINDOWS_SYMBOL_ENCODING_ID: u16 = 0;
const WINDOWS_UNICODE_BMP_ENCODING_ID: u16 = 1;
match platform_id {
PlatformId::Unicode => true,
PlatformId::Windows => matches!(
encoding_id,
WINDOWS_SYMBOL_ENCODING_ID | WINDOWS_UNICODE_BMP_ENCODING_ID
),
_ => false,
}
}
#[derive(Clone, Copy)]
struct NameRecord {
platform_id: PlatformId,
encoding_id: u16,
language_id: u16,
name_id: u16,
length: u16,
offset: Offset16,
}
impl FromData for NameRecord {
const SIZE: usize = 12;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(NameRecord {
platform_id: s.read::<PlatformId>()?,
encoding_id: s.read::<u16>()?,
language_id: s.read::<u16>()?,
name_id: s.read::<u16>()?,
length: s.read::<u16>()?,
offset: s.read::<Offset16>()?,
})
}
}
/// A [Name Record](https://docs.microsoft.com/en-us/typography/opentype/spec/name#name-records).
#[derive(Clone, Copy)]
pub struct Name<'a> {
/// A platform ID.
pub platform_id: PlatformId,
/// A platform-specific encoding ID.
pub encoding_id: u16,
/// A language ID.
pub language_id: u16,
/// A [Name ID](https://docs.microsoft.com/en-us/typography/opentype/spec/name#name-ids).
///
/// A predefined list of ID's can be found in the [`name_id`](name_id/index.html) module.
pub name_id: u16,
/// A raw name data.
///
/// Can be in any encoding. Can be empty.
pub name: &'a [u8],
}
impl<'a> Name<'a> {
/// Returns the Name's data as a UTF-8 string.
///
/// Only Unicode names are supported. And since they are stored as UTF-16BE,
/// we can't return `&str` and have to allocate a `String`.
///
/// Supports:
/// - Unicode Platform ID
/// - Windows Platform ID + Symbol
/// - Windows Platform ID + Unicode BMP
#[cfg(feature = "std")]
#[inline(never)]
pub fn to_string(&self) -> Option<String> {
if self.is_unicode() {
self.name_from_utf16_be()
} else {
None
}
}
/// Checks that the current Name data has a Unicode encoding.
#[inline]
pub fn is_unicode(&self) -> bool {
is_unicode_encoding(self.platform_id, self.encoding_id)
}
#[cfg(feature = "std")]
#[inline(never)]
fn name_from_utf16_be(&self) -> Option<String> {
let mut name: Vec<u16> = Vec::new();
for c in LazyArray16::<u16>::new(self.name) {
name.push(c);
}
String::from_utf16(&name).ok()
}
/// Returns a Name language.
pub fn language(&self) -> Language {
if self.platform_id == PlatformId::Windows {
Language::windows_language(self.language_id)
} else if self.platform_id == PlatformId::Macintosh
&& self.encoding_id == 0
&& self.language_id == 0
{
Language::English_UnitedStates
} else {
Language::Unknown
}
}
}
#[cfg(feature = "std")]
impl<'a> core::fmt::Debug for Name<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
let name = self.to_string();
f.debug_struct("Name")
.field("name", &name.as_deref().unwrap_or("unsupported encoding"))
.field("platform_id", &self.platform_id)
.field("encoding_id", &self.encoding_id)
.field("language_id", &self.language_id)
.field("language", &self.language())
.field("name_id", &self.name_id)
.finish()
}
}
#[cfg(not(feature = "std"))]
impl<'a> core::fmt::Debug for Name<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.debug_struct("Name")
.field("name", &self.name)
.field("platform_id", &self.platform_id)
.field("encoding_id", &self.encoding_id)
.field("language_id", &self.language_id)
.field("language", &self.language())
.field("name_id", &self.name_id)
.finish()
}
}
/// A list of face names.
#[derive(Clone, Copy, Default)]
pub struct Names<'a> {
records: LazyArray16<'a, NameRecord>,
storage: &'a [u8],
}
impl<'a> Names<'a> {
/// Returns a name at index.
pub fn get(&self, index: u16) -> Option<Name<'a>> {
let record = self.records.get(index)?;
let name_start = record.offset.to_usize();
let name_end = name_start + usize::from(record.length);
let name = self.storage.get(name_start..name_end)?;
Some(Name {
platform_id: record.platform_id,
encoding_id: record.encoding_id,
language_id: record.language_id,
name_id: record.name_id,
name,
})
}
/// Returns a number of name records.
pub fn len(&self) -> u16 {
self.records.len()
}
/// Checks if there are any name records.
pub fn is_empty(&self) -> bool {
self.records.is_empty()
}
}
impl core::fmt::Debug for Names<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Names {{ ... }}")
}
}
impl<'a> IntoIterator for Names<'a> {
type Item = Name<'a>;
type IntoIter = NamesIter<'a>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
NamesIter {
names: self,
index: 0,
}
}
}
/// An iterator over face names.
#[derive(Clone, Copy)]
#[allow(missing_debug_implementations)]
pub struct NamesIter<'a> {
names: Names<'a>,
index: u16,
}
impl<'a> Iterator for NamesIter<'a> {
type Item = Name<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.index < self.names.len() {
self.index += 1;
self.names.get(self.index - 1)
} else {
None
}
}
#[inline]
fn count(self) -> usize {
usize::from(self.names.len().saturating_sub(self.index))
}
}
/// A [Naming Table](
/// https://docs.microsoft.com/en-us/typography/opentype/spec/name).
#[derive(Clone, Copy, Default, Debug)]
pub struct Table<'a> {
/// A list of names.
pub names: Names<'a>,
}
impl<'a> Table<'a> {
/// Parses a table from raw data.
pub fn parse(data: &'a [u8]) -> Option<Self> {
// https://docs.microsoft.com/en-us/typography/opentype/spec/name#naming-table-format-1
const LANG_TAG_RECORD_SIZE: u16 = 4;
let mut s = Stream::new(data);
let version = s.read::<u16>()?;
let count = s.read::<u16>()?;
let storage_offset = s.read::<Offset16>()?.to_usize();
if version == 0 {
// Do nothing.
} else if version == 1 {
let lang_tag_count = s.read::<u16>()?;
let lang_tag_len = lang_tag_count.checked_mul(LANG_TAG_RECORD_SIZE)?;
s.advance(usize::from(lang_tag_len)); // langTagRecords
} else {
// Unsupported version.
return None;
}
let records = s.read_array16::<NameRecord>(count)?;
if s.offset() < storage_offset {
s.advance(storage_offset - s.offset());
}
let storage = s.tail()?;
Some(Table {
names: Names { records, storage },
})
}
}

620
vendor/ttf-parser/src/tables/os2.rs vendored Normal file
View File

@@ -0,0 +1,620 @@
//! A [OS/2 and Windows Metrics Table](https://docs.microsoft.com/en-us/typography/opentype/spec/os2)
//! implementation.
use crate::parser::Stream;
use crate::LineMetrics;
const WEIGHT_CLASS_OFFSET: usize = 4;
const WIDTH_CLASS_OFFSET: usize = 6;
const TYPE_OFFSET: usize = 8;
const Y_SUBSCRIPT_X_SIZE_OFFSET: usize = 10;
const Y_SUPERSCRIPT_X_SIZE_OFFSET: usize = 18;
const Y_STRIKEOUT_SIZE_OFFSET: usize = 26;
const Y_STRIKEOUT_POSITION_OFFSET: usize = 28;
const UNICODE_RANGES_OFFSET: usize = 42;
const SELECTION_OFFSET: usize = 62;
const TYPO_ASCENDER_OFFSET: usize = 68;
const TYPO_DESCENDER_OFFSET: usize = 70;
const TYPO_LINE_GAP_OFFSET: usize = 72;
const WIN_ASCENT: usize = 74;
const WIN_DESCENT: usize = 76;
const X_HEIGHT_OFFSET: usize = 86;
const CAP_HEIGHT_OFFSET: usize = 88;
/// A face [weight](https://docs.microsoft.com/en-us/typography/opentype/spec/os2#usweightclass).
#[allow(missing_docs)]
#[derive(Clone, Copy, Eq, PartialEq, Debug, Hash)]
pub enum Weight {
Thin,
ExtraLight,
Light,
Normal,
Medium,
SemiBold,
Bold,
ExtraBold,
Black,
Other(u16),
}
impl Weight {
/// Returns a numeric representation of a weight.
#[inline]
pub fn to_number(self) -> u16 {
match self {
Weight::Thin => 100,
Weight::ExtraLight => 200,
Weight::Light => 300,
Weight::Normal => 400,
Weight::Medium => 500,
Weight::SemiBold => 600,
Weight::Bold => 700,
Weight::ExtraBold => 800,
Weight::Black => 900,
Weight::Other(n) => n,
}
}
}
impl From<u16> for Weight {
#[inline]
fn from(value: u16) -> Self {
match value {
100 => Weight::Thin,
200 => Weight::ExtraLight,
300 => Weight::Light,
400 => Weight::Normal,
500 => Weight::Medium,
600 => Weight::SemiBold,
700 => Weight::Bold,
800 => Weight::ExtraBold,
900 => Weight::Black,
_ => Weight::Other(value),
}
}
}
impl Default for Weight {
#[inline]
fn default() -> Self {
Weight::Normal
}
}
/// A face [width](https://docs.microsoft.com/en-us/typography/opentype/spec/os2#uswidthclass).
#[allow(missing_docs)]
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
pub enum Width {
UltraCondensed,
ExtraCondensed,
Condensed,
SemiCondensed,
Normal,
SemiExpanded,
Expanded,
ExtraExpanded,
UltraExpanded,
}
impl Width {
/// Returns a numeric representation of a width.
#[inline]
pub fn to_number(self) -> u16 {
match self {
Width::UltraCondensed => 1,
Width::ExtraCondensed => 2,
Width::Condensed => 3,
Width::SemiCondensed => 4,
Width::Normal => 5,
Width::SemiExpanded => 6,
Width::Expanded => 7,
Width::ExtraExpanded => 8,
Width::UltraExpanded => 9,
}
}
}
impl Default for Width {
#[inline]
fn default() -> Self {
Width::Normal
}
}
/// Face [permissions](https://docs.microsoft.com/en-us/typography/opentype/spec/os2#fst).
#[allow(missing_docs)]
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
pub enum Permissions {
Installable,
Restricted,
PreviewAndPrint,
Editable,
}
/// A face style.
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub enum Style {
/// A face that is neither italic not obliqued.
Normal,
/// A form that is generally cursive in nature.
Italic,
/// A typically-sloped version of the regular face.
Oblique,
}
impl Default for Style {
#[inline]
fn default() -> Style {
Style::Normal
}
}
/// A script metrics used by subscript and superscript.
#[repr(C)]
#[derive(Clone, Copy, Eq, PartialEq, Debug, Hash)]
pub struct ScriptMetrics {
/// Horizontal face size.
pub x_size: i16,
/// Vertical face size.
pub y_size: i16,
/// X offset.
pub x_offset: i16,
/// Y offset.
pub y_offset: i16,
}
// https://docs.microsoft.com/en-us/typography/opentype/spec/os2#fsselection
#[derive(Clone, Copy)]
struct SelectionFlags(u16);
#[rustfmt::skip]
impl SelectionFlags {
#[inline] fn italic(self) -> bool { self.0 & (1 << 0) != 0 }
#[inline] fn bold(self) -> bool { self.0 & (1 << 5) != 0 }
// #[inline] fn regular(self) -> bool { self.0 & (1 << 6) != 0 }
#[inline] fn use_typo_metrics(self) -> bool { self.0 & (1 << 7) != 0 }
#[inline] fn oblique(self) -> bool { self.0 & (1 << 9) != 0 }
}
/// [Unicode Ranges](https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ur).
#[derive(Clone, Copy, Default, Debug)]
pub struct UnicodeRanges(u128);
impl UnicodeRanges {
/// Checks if ranges contain the specified character.
pub fn contains_char(&self, c: char) -> bool {
let range = char_range_index(c);
if range >= 0 {
self.0 & (1 << range as u128) != 0
} else {
false
}
}
}
fn char_range_index(c: char) -> i8 {
match c as u32 {
0x0000..=0x007F => 0,
0x0080..=0x00FF => 1,
0x0100..=0x017F => 2,
0x0180..=0x024F => 3,
0x0250..=0x02AF => 4,
0x1D00..=0x1DBF => 4,
0x02B0..=0x02FF => 5,
0xA700..=0xA71F => 5,
0x0300..=0x036F => 6,
0x1DC0..=0x1DFF => 6,
0x0370..=0x03FF => 7,
0x2C80..=0x2CFF => 8,
0x0400..=0x052F => 9,
0x2DE0..=0x2DFF => 9,
0xA640..=0xA69F => 9,
0x0530..=0x058F => 10,
0x0590..=0x05FF => 11,
0xA500..=0xA63F => 12,
0x0600..=0x06FF => 13,
0x0750..=0x077F => 13,
0x07C0..=0x07FF => 14,
0x0900..=0x097F => 15,
0x0980..=0x09FF => 16,
0x0A00..=0x0A7F => 17,
0x0A80..=0x0AFF => 18,
0x0B00..=0x0B7F => 19,
0x0B80..=0x0BFF => 20,
0x0C00..=0x0C7F => 21,
0x0C80..=0x0CFF => 22,
0x0D00..=0x0D7F => 23,
0x0E00..=0x0E7F => 24,
0x0E80..=0x0EFF => 25,
0x10A0..=0x10FF => 26,
0x2D00..=0x2D2F => 26,
0x1B00..=0x1B7F => 27,
0x1100..=0x11FF => 28,
0x1E00..=0x1EFF => 29,
0x2C60..=0x2C7F => 29,
0xA720..=0xA7FF => 29,
0x1F00..=0x1FFF => 30,
0x2000..=0x206F => 31,
0x2E00..=0x2E7F => 31,
0x2070..=0x209F => 32,
0x20A0..=0x20CF => 33,
0x20D0..=0x20FF => 34,
0x2100..=0x214F => 35,
0x2150..=0x218F => 36,
0x2190..=0x21FF => 37,
0x27F0..=0x27FF => 37,
0x2900..=0x297F => 37,
0x2B00..=0x2BFF => 37,
0x2200..=0x22FF => 38,
0x2A00..=0x2AFF => 38,
0x27C0..=0x27EF => 38,
0x2980..=0x29FF => 38,
0x2300..=0x23FF => 39,
0x2400..=0x243F => 40,
0x2440..=0x245F => 41,
0x2460..=0x24FF => 42,
0x2500..=0x257F => 43,
0x2580..=0x259F => 44,
0x25A0..=0x25FF => 45,
0x2600..=0x26FF => 46,
0x2700..=0x27BF => 47,
0x3000..=0x303F => 48,
0x3040..=0x309F => 49,
0x30A0..=0x30FF => 50,
0x31F0..=0x31FF => 50,
0x3100..=0x312F => 51,
0x31A0..=0x31BF => 51,
0x3130..=0x318F => 52,
0xA840..=0xA87F => 53,
0x3200..=0x32FF => 54,
0x3300..=0x33FF => 55,
0xAC00..=0xD7AF => 56,
// Ignore Non-Plane 0 (57), since this is not a real range.
0x10900..=0x1091F => 58,
0x4E00..=0x9FFF => 59,
0x2E80..=0x2FDF => 59,
0x2FF0..=0x2FFF => 59,
0x3400..=0x4DBF => 59,
0x20000..=0x2A6DF => 59,
0x3190..=0x319F => 59,
0xE000..=0xF8FF => 60,
0x31C0..=0x31EF => 61,
0xF900..=0xFAFF => 61,
0x2F800..=0x2FA1F => 61,
0xFB00..=0xFB4F => 62,
0xFB50..=0xFDFF => 63,
0xFE20..=0xFE2F => 64,
0xFE10..=0xFE1F => 65,
0xFE30..=0xFE4F => 65,
0xFE50..=0xFE6F => 66,
0xFE70..=0xFEFF => 67,
0xFF00..=0xFFEF => 68,
0xFFF0..=0xFFFF => 69,
0x0F00..=0x0FFF => 70,
0x0700..=0x074F => 71,
0x0780..=0x07BF => 72,
0x0D80..=0x0DFF => 73,
0x1000..=0x109F => 74,
0x1200..=0x139F => 75,
0x2D80..=0x2DDF => 75,
0x13A0..=0x13FF => 76,
0x1400..=0x167F => 77,
0x1680..=0x169F => 78,
0x16A0..=0x16FF => 79,
0x1780..=0x17FF => 80,
0x19E0..=0x19FF => 80,
0x1800..=0x18AF => 81,
0x2800..=0x28FF => 82,
0xA000..=0xA48F => 83,
0xA490..=0xA4CF => 83,
0x1700..=0x177F => 84,
0x10300..=0x1032F => 85,
0x10330..=0x1034F => 86,
0x10400..=0x1044F => 87,
0x1D000..=0x1D24F => 88,
0x1D400..=0x1D7FF => 89,
0xF0000..=0xFFFFD => 90,
0x100000..=0x10FFFD => 90,
0xFE00..=0xFE0F => 91,
0xE0100..=0xE01EF => 91,
0xE0000..=0xE007F => 92,
0x1900..=0x194F => 93,
0x1950..=0x197F => 94,
0x1980..=0x19DF => 95,
0x1A00..=0x1A1F => 96,
0x2C00..=0x2C5F => 97,
0x2D30..=0x2D7F => 98,
0x4DC0..=0x4DFF => 99,
0xA800..=0xA82F => 100,
0x10000..=0x1013F => 101,
0x10140..=0x1018F => 102,
0x10380..=0x1039F => 103,
0x103A0..=0x103DF => 104,
0x10450..=0x1047F => 105,
0x10480..=0x104AF => 106,
0x10800..=0x1083F => 107,
0x10A00..=0x10A5F => 108,
0x1D300..=0x1D35F => 109,
0x12000..=0x123FF => 110,
0x12400..=0x1247F => 110,
0x1D360..=0x1D37F => 111,
0x1B80..=0x1BBF => 112,
0x1C00..=0x1C4F => 113,
0x1C50..=0x1C7F => 114,
0xA880..=0xA8DF => 115,
0xA900..=0xA92F => 116,
0xA930..=0xA95F => 117,
0xAA00..=0xAA5F => 118,
0x10190..=0x101CF => 119,
0x101D0..=0x101FF => 120,
0x102A0..=0x102DF => 121,
0x10280..=0x1029F => 121,
0x10920..=0x1093F => 121,
0x1F030..=0x1F09F => 122,
0x1F000..=0x1F02F => 122,
_ => -1,
}
}
/// A [OS/2 and Windows Metrics Table](https://docs.microsoft.com/en-us/typography/opentype/spec/os2).
#[derive(Clone, Copy)]
pub struct Table<'a> {
/// Table version.
pub version: u8,
data: &'a [u8],
}
impl<'a> Table<'a> {
/// Parses a table from raw data.
pub fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let version = s.read::<u16>()?;
let table_len = match version {
0 => 78,
1 => 86,
2 => 96,
3 => 96,
4 => 96,
5 => 100,
_ => return None,
};
// Do not check the exact length, because some fonts include
// padding in table's length in table records, which is incorrect.
if data.len() < table_len {
return None;
}
Some(Table {
version: version as u8,
data,
})
}
/// Returns weight class.
#[inline]
pub fn weight(&self) -> Weight {
Weight::from(Stream::read_at::<u16>(self.data, WEIGHT_CLASS_OFFSET).unwrap_or(0))
}
/// Returns face width.
#[inline]
pub fn width(&self) -> Width {
match Stream::read_at::<u16>(self.data, WIDTH_CLASS_OFFSET).unwrap_or(0) {
1 => Width::UltraCondensed,
2 => Width::ExtraCondensed,
3 => Width::Condensed,
4 => Width::SemiCondensed,
5 => Width::Normal,
6 => Width::SemiExpanded,
7 => Width::Expanded,
8 => Width::ExtraExpanded,
9 => Width::UltraExpanded,
_ => Width::Normal,
}
}
/// Returns face permissions.
///
/// Returns `None` in case of a malformed value.
#[inline]
pub fn permissions(&self) -> Option<Permissions> {
let n = Stream::read_at::<u16>(self.data, TYPE_OFFSET).unwrap_or(0);
if self.version <= 2 {
// Version 2 and prior, applications are allowed to take
// the most permissive of provided flags
let permission = if n & 0xF == 0 {
Permissions::Installable
} else if n & 8 != 0 {
Permissions::Editable
} else if n & 4 != 0 {
Permissions::PreviewAndPrint
} else {
Permissions::Restricted
};
Some(permission)
} else {
// Version 3 onwards, flags must be mutually exclusive.
match n & 0xF {
0 => Some(Permissions::Installable),
2 => Some(Permissions::Restricted),
4 => Some(Permissions::PreviewAndPrint),
8 => Some(Permissions::Editable),
_ => None,
}
}
}
/// Checks if the face allows embedding a subset, further restricted by [`Self::permissions`].
#[inline]
pub fn is_subsetting_allowed(&self) -> bool {
if self.version <= 1 {
// Flag introduced in version 2
true
} else {
let n = Stream::read_at::<u16>(self.data, TYPE_OFFSET).unwrap_or(0);
n & 0x0100 == 0
}
}
/// Checks if the face allows outline data to be embedded.
///
/// If false, only bitmaps may be embedded in accordance with [`Self::permissions`].
///
/// If the font contains no bitmaps and this flag is not set, it implies no embedding is allowed.
#[inline]
pub fn is_outline_embedding_allowed(&self) -> bool {
if self.version <= 1 {
// Flag introduced in version 2
true
} else {
let n = Stream::read_at::<u16>(self.data, TYPE_OFFSET).unwrap_or(0);
n & 0x0200 == 0
}
}
/// Returns subscript metrics.
#[inline]
pub fn subscript_metrics(&self) -> ScriptMetrics {
let mut s = Stream::new_at(self.data, Y_SUBSCRIPT_X_SIZE_OFFSET).unwrap_or_default();
ScriptMetrics {
x_size: s.read::<i16>().unwrap_or(0),
y_size: s.read::<i16>().unwrap_or(0),
x_offset: s.read::<i16>().unwrap_or(0),
y_offset: s.read::<i16>().unwrap_or(0),
}
}
/// Returns superscript metrics.
#[inline]
pub fn superscript_metrics(&self) -> ScriptMetrics {
let mut s = Stream::new_at(self.data, Y_SUPERSCRIPT_X_SIZE_OFFSET).unwrap_or_default();
ScriptMetrics {
x_size: s.read::<i16>().unwrap_or(0),
y_size: s.read::<i16>().unwrap_or(0),
x_offset: s.read::<i16>().unwrap_or(0),
y_offset: s.read::<i16>().unwrap_or(0),
}
}
/// Returns strikeout metrics.
#[inline]
pub fn strikeout_metrics(&self) -> LineMetrics {
LineMetrics {
thickness: Stream::read_at::<i16>(self.data, Y_STRIKEOUT_SIZE_OFFSET).unwrap_or(0),
position: Stream::read_at::<i16>(self.data, Y_STRIKEOUT_POSITION_OFFSET).unwrap_or(0),
}
}
/// Returns Unicode ranges.
#[inline]
pub fn unicode_ranges(&self) -> UnicodeRanges {
let mut s = Stream::new_at(self.data, UNICODE_RANGES_OFFSET).unwrap();
let n1 = s.read::<u32>().unwrap_or(0) as u128;
let n2 = s.read::<u32>().unwrap_or(0) as u128;
let n3 = s.read::<u32>().unwrap_or(0) as u128;
let n4 = s.read::<u32>().unwrap_or(0) as u128;
UnicodeRanges(n4 << 96 | n3 << 64 | n2 << 32 | n1)
}
#[inline]
fn fs_selection(&self) -> u16 {
Stream::read_at::<u16>(self.data, SELECTION_OFFSET).unwrap_or(0)
}
/// Returns style.
pub fn style(&self) -> Style {
let flags = SelectionFlags(self.fs_selection());
if flags.italic() {
Style::Italic
} else if self.version >= 4 && flags.oblique() {
Style::Oblique
} else {
Style::Normal
}
}
/// Checks if face is bold.
///
/// Do not confuse with [`Weight::Bold`].
#[inline]
pub fn is_bold(&self) -> bool {
SelectionFlags(self.fs_selection()).bold()
}
/// Checks if typographic metrics should be used.
#[inline]
pub fn use_typographic_metrics(&self) -> bool {
if self.version < 4 {
false
} else {
SelectionFlags(self.fs_selection()).use_typo_metrics()
}
}
/// Returns typographic ascender.
#[inline]
pub fn typographic_ascender(&self) -> i16 {
Stream::read_at::<i16>(self.data, TYPO_ASCENDER_OFFSET).unwrap_or(0)
}
/// Returns typographic descender.
#[inline]
pub fn typographic_descender(&self) -> i16 {
Stream::read_at::<i16>(self.data, TYPO_DESCENDER_OFFSET).unwrap_or(0)
}
/// Returns typographic line gap.
#[inline]
pub fn typographic_line_gap(&self) -> i16 {
Stream::read_at::<i16>(self.data, TYPO_LINE_GAP_OFFSET).unwrap_or(0)
}
/// Returns Windows ascender.
#[inline]
pub fn windows_ascender(&self) -> i16 {
Stream::read_at::<i16>(self.data, WIN_ASCENT).unwrap_or(0)
}
/// Returns Windows descender.
#[inline]
pub fn windows_descender(&self) -> i16 {
// Should be negated.
-Stream::read_at::<i16>(self.data, WIN_DESCENT).unwrap_or(0)
}
/// Returns x height.
///
/// Returns `None` version is < 2.
#[inline]
pub fn x_height(&self) -> Option<i16> {
if self.version < 2 {
None
} else {
Stream::read_at::<i16>(self.data, X_HEIGHT_OFFSET)
}
}
/// Returns capital height.
///
/// Returns `None` version is < 2.
#[inline]
pub fn capital_height(&self) -> Option<i16> {
if self.version < 2 {
None
} else {
Stream::read_at::<i16>(self.data, CAP_HEIGHT_OFFSET)
}
}
}
impl core::fmt::Debug for Table<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Table {{ ... }}")
}
}

423
vendor/ttf-parser/src/tables/post.rs vendored Normal file
View File

@@ -0,0 +1,423 @@
//! A [PostScript Table](
//! https://docs.microsoft.com/en-us/typography/opentype/spec/post) implementation.
use crate::parser::{Fixed, LazyArray16, Stream};
#[cfg(feature = "glyph-names")]
use crate::GlyphId;
use crate::LineMetrics;
const ITALIC_ANGLE_OFFSET: usize = 4;
const UNDERLINE_POSITION_OFFSET: usize = 8;
const UNDERLINE_THICKNESS_OFFSET: usize = 10;
const IS_FIXED_PITCH_OFFSET: usize = 12;
// https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6post.html
/// A list of Macintosh glyph names.
#[cfg(feature = "glyph-names")]
const MACINTOSH_NAMES: &[&str] = &[
".notdef",
".null",
"nonmarkingreturn",
"space",
"exclam",
"quotedbl",
"numbersign",
"dollar",
"percent",
"ampersand",
"quotesingle",
"parenleft",
"parenright",
"asterisk",
"plus",
"comma",
"hyphen",
"period",
"slash",
"zero",
"one",
"two",
"three",
"four",
"five",
"six",
"seven",
"eight",
"nine",
"colon",
"semicolon",
"less",
"equal",
"greater",
"question",
"at",
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"I",
"J",
"K",
"L",
"M",
"N",
"O",
"P",
"Q",
"R",
"S",
"T",
"U",
"V",
"W",
"X",
"Y",
"Z",
"bracketleft",
"backslash",
"bracketright",
"asciicircum",
"underscore",
"grave",
"a",
"b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
"m",
"n",
"o",
"p",
"q",
"r",
"s",
"t",
"u",
"v",
"w",
"x",
"y",
"z",
"braceleft",
"bar",
"braceright",
"asciitilde",
"Adieresis",
"Aring",
"Ccedilla",
"Eacute",
"Ntilde",
"Odieresis",
"Udieresis",
"aacute",
"agrave",
"acircumflex",
"adieresis",
"atilde",
"aring",
"ccedilla",
"eacute",
"egrave",
"ecircumflex",
"edieresis",
"iacute",
"igrave",
"icircumflex",
"idieresis",
"ntilde",
"oacute",
"ograve",
"ocircumflex",
"odieresis",
"otilde",
"uacute",
"ugrave",
"ucircumflex",
"udieresis",
"dagger",
"degree",
"cent",
"sterling",
"section",
"bullet",
"paragraph",
"germandbls",
"registered",
"copyright",
"trademark",
"acute",
"dieresis",
"notequal",
"AE",
"Oslash",
"infinity",
"plusminus",
"lessequal",
"greaterequal",
"yen",
"mu",
"partialdiff",
"summation",
"product",
"pi",
"integral",
"ordfeminine",
"ordmasculine",
"Omega",
"ae",
"oslash",
"questiondown",
"exclamdown",
"logicalnot",
"radical",
"florin",
"approxequal",
"Delta",
"guillemotleft",
"guillemotright",
"ellipsis",
"nonbreakingspace",
"Agrave",
"Atilde",
"Otilde",
"OE",
"oe",
"endash",
"emdash",
"quotedblleft",
"quotedblright",
"quoteleft",
"quoteright",
"divide",
"lozenge",
"ydieresis",
"Ydieresis",
"fraction",
"currency",
"guilsinglleft",
"guilsinglright",
"fi",
"fl",
"daggerdbl",
"periodcentered",
"quotesinglbase",
"quotedblbase",
"perthousand",
"Acircumflex",
"Ecircumflex",
"Aacute",
"Edieresis",
"Egrave",
"Iacute",
"Icircumflex",
"Idieresis",
"Igrave",
"Oacute",
"Ocircumflex",
"apple",
"Ograve",
"Uacute",
"Ucircumflex",
"Ugrave",
"dotlessi",
"circumflex",
"tilde",
"macron",
"breve",
"dotaccent",
"ring",
"cedilla",
"hungarumlaut",
"ogonek",
"caron",
"Lslash",
"lslash",
"Scaron",
"scaron",
"Zcaron",
"zcaron",
"brokenbar",
"Eth",
"eth",
"Yacute",
"yacute",
"Thorn",
"thorn",
"minus",
"multiply",
"onesuperior",
"twosuperior",
"threesuperior",
"onehalf",
"onequarter",
"threequarters",
"franc",
"Gbreve",
"gbreve",
"Idotaccent",
"Scedilla",
"scedilla",
"Cacute",
"cacute",
"Ccaron",
"ccaron",
"dcroat",
];
/// An iterator over glyph names.
///
/// The `post` table doesn't provide the glyph names count,
/// so we have to simply iterate over all of them to find it out.
#[derive(Clone, Copy, Default)]
pub struct Names<'a> {
data: &'a [u8],
offset: usize,
}
impl core::fmt::Debug for Names<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Names {{ ... }}")
}
}
impl<'a> Iterator for Names<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<Self::Item> {
// Glyph names are stored as Pascal Strings.
// Meaning u8 (len) + [u8] (data).
if self.offset >= self.data.len() {
return None;
}
let len = self.data[self.offset];
self.offset += 1;
// An empty name is an error.
if len == 0 {
return None;
}
let name = self.data.get(self.offset..self.offset + usize::from(len))?;
self.offset += usize::from(len);
core::str::from_utf8(name).ok()
}
}
/// A [PostScript Table](https://docs.microsoft.com/en-us/typography/opentype/spec/post).
#[derive(Clone, Copy, Debug)]
pub struct Table<'a> {
/// Italic angle in counter-clockwise degrees from the vertical.
pub italic_angle: f32,
/// Underline metrics.
pub underline_metrics: LineMetrics,
/// Flag that indicates that the font is monospaced.
pub is_monospaced: bool,
glyph_indexes: LazyArray16<'a, u16>,
names_data: &'a [u8],
}
impl<'a> Table<'a> {
/// Parses a table from raw data.
pub fn parse(data: &'a [u8]) -> Option<Self> {
// Do not check the exact length, because some fonts include
// padding in table's length in table records, which is incorrect.
if data.len() < 32 {
return None;
}
let version = Stream::new(data).read::<u32>()?;
if !(version == 0x00010000
|| version == 0x00020000
|| version == 0x00025000
|| version == 0x00030000
|| version == 0x00040000)
{
return None;
}
let italic_angle = Stream::read_at::<Fixed>(data, ITALIC_ANGLE_OFFSET)?.0;
let underline_metrics = LineMetrics {
position: Stream::read_at::<i16>(data, UNDERLINE_POSITION_OFFSET)?,
thickness: Stream::read_at::<i16>(data, UNDERLINE_THICKNESS_OFFSET)?,
};
let is_monospaced = Stream::read_at::<u32>(data, IS_FIXED_PITCH_OFFSET)? != 0;
let mut names_data: &[u8] = &[];
let mut glyph_indexes = LazyArray16::default();
// Only version 2.0 of the table has data at the end.
if version == 0x00020000 {
let mut s = Stream::new_at(data, 32)?;
let indexes_count = s.read::<u16>()?;
glyph_indexes = s.read_array16::<u16>(indexes_count)?;
names_data = s.tail()?;
}
Some(Table {
italic_angle,
underline_metrics,
is_monospaced,
names_data,
glyph_indexes,
})
}
/// Returns a glyph name by ID.
#[cfg(feature = "glyph-names")]
pub fn glyph_name(&self, glyph_id: GlyphId) -> Option<&'a str> {
let mut index = self.glyph_indexes.get(glyph_id.0)?;
// 'If the name index is between 0 and 257, treat the name index
// as a glyph index in the Macintosh standard order.'
if usize::from(index) < MACINTOSH_NAMES.len() {
Some(MACINTOSH_NAMES[usize::from(index)])
} else {
// 'If the name index is between 258 and 65535, then subtract 258 and use that
// to index into the list of Pascal strings at the end of the table.'
index -= MACINTOSH_NAMES.len() as u16;
self.names().nth(usize::from(index))
}
}
/// Returns a glyph ID by a name.
#[cfg(feature = "glyph-names")]
pub fn glyph_index_by_name(&self, name: &str) -> Option<GlyphId> {
let id = if let Some(index) = MACINTOSH_NAMES.iter().position(|n| *n == name) {
self.glyph_indexes
.into_iter()
.position(|i| usize::from(i) == index)?
} else {
let mut index = self.names().position(|n| n == name)?;
index += MACINTOSH_NAMES.len();
self.glyph_indexes
.into_iter()
.position(|i| usize::from(i) == index)?
};
Some(GlyphId(id as u16))
}
/// Returns an iterator over glyph names.
///
/// Default/predefined names are not included. Just the one in the font file.
pub fn names(&self) -> Names<'a> {
Names {
data: self.names_data,
offset: 0,
}
}
}

252
vendor/ttf-parser/src/tables/sbix.rs vendored Normal file
View File

@@ -0,0 +1,252 @@
//! A [Standard Bitmap Graphics Table](
//! https://docs.microsoft.com/en-us/typography/opentype/spec/sbix) implementation.
use core::convert::TryFrom;
use core::num::NonZeroU16;
use crate::parser::{FromData, LazyArray16, LazyArray32, Offset, Offset32, Stream};
use crate::{GlyphId, RasterGlyphImage, RasterImageFormat, Tag};
/// A strike of glyphs.
#[derive(Clone, Copy)]
pub struct Strike<'a> {
/// The pixels per EM size for which this strike was designed.
pub pixels_per_em: u16,
/// The device pixel density (in PPI) for which this strike was designed.
pub ppi: u16,
offsets: LazyArray16<'a, Offset32>,
/// Data from the beginning of the `Strikes` table.
data: &'a [u8],
}
impl<'a> Strike<'a> {
fn parse(number_of_glyphs: u16, data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let pixels_per_em = s.read::<u16>()?;
let ppi = s.read::<u16>()?;
let offsets = s.read_array16(number_of_glyphs)?;
Some(Strike {
pixels_per_em,
ppi,
offsets,
data,
})
}
/// Returns a glyph data.
pub fn get(&self, glyph_id: GlyphId) -> Option<RasterGlyphImage<'a>> {
self.get_inner(glyph_id, 0)
}
fn get_inner(&self, glyph_id: GlyphId, depth: u8) -> Option<RasterGlyphImage<'a>> {
// Recursive `dupe`. Bail.
if depth == 10 {
return None;
}
let start = self.offsets.get(glyph_id.0)?.to_usize();
let end = self.offsets.get(glyph_id.0.checked_add(1)?)?.to_usize();
if start == end {
return None;
}
let data_len = end.checked_sub(start)?.checked_sub(8)?; // 8 is a Glyph data header size.
let mut s = Stream::new_at(self.data, start)?;
let x = s.read::<i16>()?;
let y = s.read::<i16>()?;
let image_type = s.read::<Tag>()?;
let image_data = s.read_bytes(data_len)?;
// We do ignore `pdf` and `mask` intentionally, because Apple docs state that:
// 'Support for the 'pdf ' and 'mask' data types and sbixDrawOutlines flag
// are planned for future releases of iOS and OS X.'
let format = match &image_type.to_bytes() {
b"png " => RasterImageFormat::PNG,
b"dupe" => {
// 'The special graphicType of 'dupe' indicates that
// the data field contains a glyph ID. The bitmap data for
// the indicated glyph should be used for the current glyph.'
let glyph_id = GlyphId::parse(image_data)?;
// TODO: The spec isn't clear about which x/y values should we use.
// The current glyph or the referenced one.
return self.get_inner(glyph_id, depth + 1);
}
_ => {
// TODO: support JPEG and TIFF
return None;
}
};
let (width, height) = png_size(image_data)?;
Some(RasterGlyphImage {
x,
y,
width,
height,
pixels_per_em: self.pixels_per_em,
format,
data: image_data,
})
}
/// Returns the number of glyphs in this strike.
#[inline]
pub fn len(&self) -> u16 {
// The last offset simply indicates the glyph data end. We don't need it.
self.offsets.len() - 1
}
/// Checks if there are any glyphs.
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl core::fmt::Debug for Strike<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Strike {{ ... }}")
}
}
/// A list of [`Strike`]s.
#[derive(Clone, Copy)]
pub struct Strikes<'a> {
/// `sbix` table data.
data: &'a [u8],
// Offsets from the beginning of the `sbix` table.
offsets: LazyArray32<'a, Offset32>,
// The total number of glyphs in the face + 1. From the `maxp` table.
number_of_glyphs: u16,
}
impl<'a> Strikes<'a> {
/// Returns a strike at the index.
pub fn get(&self, index: u32) -> Option<Strike<'a>> {
let offset = self.offsets.get(index)?.to_usize();
let data = self.data.get(offset..)?;
Strike::parse(self.number_of_glyphs, data)
}
/// Returns the number of strikes.
#[inline]
pub fn len(&self) -> u32 {
self.offsets.len()
}
/// Checks if there are any strikes.
pub fn is_empty(&self) -> bool {
self.offsets.is_empty()
}
}
impl core::fmt::Debug for Strikes<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Strikes {{ ... }}")
}
}
impl<'a> IntoIterator for Strikes<'a> {
type Item = Strike<'a>;
type IntoIter = StrikesIter<'a>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
StrikesIter {
strikes: self,
index: 0,
}
}
}
/// An iterator over [`Strikes`].
#[allow(missing_debug_implementations)]
pub struct StrikesIter<'a> {
strikes: Strikes<'a>,
index: u32,
}
impl<'a> Iterator for StrikesIter<'a> {
type Item = Strike<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.index < self.strikes.len() {
self.index += 1;
self.strikes.get(self.index - 1)
} else {
None
}
}
}
/// A [Standard Bitmap Graphics Table](
/// https://docs.microsoft.com/en-us/typography/opentype/spec/sbix).
#[derive(Clone, Copy, Debug)]
pub struct Table<'a> {
/// A list of [`Strike`]s.
pub strikes: Strikes<'a>,
}
impl<'a> Table<'a> {
/// Parses a table from raw data.
///
/// - `number_of_glyphs` is from the `maxp` table.
pub fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Option<Self> {
let number_of_glyphs = number_of_glyphs.get().checked_add(1)?;
let mut s = Stream::new(data);
let version = s.read::<u16>()?;
if version != 1 {
return None;
}
s.skip::<u16>(); // flags
let strikes_count = s.read::<u32>()?;
if strikes_count == 0 {
return None;
}
let offsets = s.read_array32::<Offset32>(strikes_count)?;
Some(Table {
strikes: Strikes {
data,
offsets,
number_of_glyphs,
},
})
}
/// Selects the best matching [`Strike`] based on `pixels_per_em`.
pub fn best_strike(&self, pixels_per_em: u16) -> Option<Strike<'a>> {
let mut idx = 0;
let mut max_ppem = 0;
for (i, strike) in self.strikes.into_iter().enumerate() {
if (pixels_per_em <= strike.pixels_per_em && strike.pixels_per_em < max_ppem)
|| (pixels_per_em > max_ppem && strike.pixels_per_em > max_ppem)
{
idx = i as u32;
max_ppem = strike.pixels_per_em;
}
}
self.strikes.get(idx)
}
}
// The `sbix` table doesn't store the image size, so we have to parse it manually.
// Which is quite simple in case of PNG, but way more complex for JPEG.
// Therefore we are omitting it for now.
fn png_size(data: &[u8]) -> Option<(u16, u16)> {
// PNG stores its size as u32 BE at a fixed offset.
let mut s = Stream::new_at(data, 16)?;
let width = s.read::<u32>()?;
let height = s.read::<u32>()?;
// PNG size larger than u16::MAX is an error.
Some((u16::try_from(width).ok()?, u16::try_from(height).ok()?))
}

173
vendor/ttf-parser/src/tables/svg.rs vendored Normal file
View File

@@ -0,0 +1,173 @@
//! An [SVG Table](https://docs.microsoft.com/en-us/typography/opentype/spec/svg) implementation.
use crate::parser::{FromData, LazyArray16, NumFrom, Offset, Offset32, Stream};
use crate::GlyphId;
/// An [SVG documents](
/// https://docs.microsoft.com/en-us/typography/opentype/spec/svg#svg-document-list).
#[derive(Clone, Copy, Debug)]
pub struct SvgDocument<'a> {
/// The SVG document data.
///
/// Can be stored as a string or as a gzip compressed data, aka SVGZ.
pub data: &'a [u8],
/// The first glyph ID for the range covered by this record.
pub start_glyph_id: GlyphId,
/// The last glyph ID, *inclusive*, for the range covered by this record.
pub end_glyph_id: GlyphId,
}
impl SvgDocument<'_> {
/// Returns the glyphs range.
pub fn glyphs_range(&self) -> core::ops::RangeInclusive<GlyphId> {
self.start_glyph_id..=self.end_glyph_id
}
}
#[derive(Clone, Copy)]
struct SvgDocumentRecord {
start_glyph_id: GlyphId,
end_glyph_id: GlyphId,
svg_doc_offset: Option<Offset32>,
svg_doc_length: u32,
}
impl SvgDocumentRecord {
fn glyphs_range(&self) -> core::ops::RangeInclusive<GlyphId> {
self.start_glyph_id..=self.end_glyph_id
}
}
impl FromData for SvgDocumentRecord {
const SIZE: usize = 12;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(SvgDocumentRecord {
start_glyph_id: s.read::<GlyphId>()?,
end_glyph_id: s.read::<GlyphId>()?,
svg_doc_offset: s.read::<Option<Offset32>>()?,
svg_doc_length: s.read::<u32>()?,
})
}
}
/// A list of [SVG documents](
/// https://docs.microsoft.com/en-us/typography/opentype/spec/svg#svg-document-list).
#[derive(Clone, Copy)]
pub struct SvgDocumentsList<'a> {
data: &'a [u8],
records: LazyArray16<'a, SvgDocumentRecord>,
}
impl<'a> SvgDocumentsList<'a> {
/// Returns SVG document data at index.
///
/// `index` is not a GlyphId. You should use [`find()`](SvgDocumentsList::find) instead.
#[inline]
pub fn get(&self, index: u16) -> Option<SvgDocument<'a>> {
let record = self.records.get(index)?;
let offset = record.svg_doc_offset?.to_usize();
self.data
.get(offset..offset + usize::num_from(record.svg_doc_length))
.map(|data| SvgDocument {
data,
start_glyph_id: record.start_glyph_id,
end_glyph_id: record.end_glyph_id,
})
}
/// Returns a SVG document data by glyph ID.
#[inline]
pub fn find(&self, glyph_id: GlyphId) -> Option<SvgDocument<'a>> {
let index = self
.records
.into_iter()
.position(|v| v.glyphs_range().contains(&glyph_id))?;
self.get(index as u16)
}
/// Returns the number of SVG documents in the list.
pub fn len(&self) -> u16 {
self.records.len()
}
/// Checks if the list is empty.
pub fn is_empty(&self) -> bool {
self.records.is_empty()
}
}
impl core::fmt::Debug for SvgDocumentsList<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "SvgDocumentsList {{ ... }}")
}
}
impl<'a> IntoIterator for SvgDocumentsList<'a> {
type Item = SvgDocument<'a>;
type IntoIter = SvgDocumentsListIter<'a>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
SvgDocumentsListIter {
list: self,
index: 0,
}
}
}
/// An iterator over [`SvgDocumentsList`] values.
#[derive(Clone, Copy)]
#[allow(missing_debug_implementations)]
pub struct SvgDocumentsListIter<'a> {
list: SvgDocumentsList<'a>,
index: u16,
}
impl<'a> Iterator for SvgDocumentsListIter<'a> {
type Item = SvgDocument<'a>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.index < self.list.len() {
self.index += 1;
self.list.get(self.index - 1)
} else {
None
}
}
#[inline]
fn count(self) -> usize {
usize::from(self.list.len().saturating_sub(self.index))
}
}
/// An [SVG Table](https://docs.microsoft.com/en-us/typography/opentype/spec/svg).
#[derive(Clone, Copy, Debug)]
pub struct Table<'a> {
/// A list of SVG documents.
pub documents: SvgDocumentsList<'a>,
}
impl<'a> Table<'a> {
/// Parses a table from raw data.
pub fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
s.skip::<u16>(); // version
let doc_list_offset = s.read::<Option<Offset32>>()??;
let mut s = Stream::new_at(data, doc_list_offset.to_usize())?;
let count = s.read::<u16>()?;
let records = s.read_array16::<SvgDocumentRecord>(count)?;
Some(Table {
documents: SvgDocumentsList {
data: &data[doc_list_offset.0 as usize..],
records,
},
})
}
}

181
vendor/ttf-parser/src/tables/trak.rs vendored Normal file
View File

@@ -0,0 +1,181 @@
//! A [Tracking Table](
//! https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6trak.html) implementation.
use crate::parser::{Fixed, FromData, LazyArray16, Offset, Offset16, Offset32, Stream};
#[derive(Clone, Copy, Debug)]
struct TrackTableRecord {
value: Fixed,
name_id: u16,
offset: Offset16, // Offset from start of the table.
}
impl FromData for TrackTableRecord {
const SIZE: usize = 8;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(TrackTableRecord {
value: s.read::<Fixed>()?,
name_id: s.read::<u16>()?,
offset: s.read::<Offset16>()?,
})
}
}
/// A single track.
#[derive(Clone, Copy, Debug)]
pub struct Track<'a> {
/// A track value.
pub value: f32,
/// The `name` table index for the track's name.
pub name_index: u16,
/// A list of tracking values for each size.
pub values: LazyArray16<'a, i16>,
}
/// A list of tracks.
#[derive(Clone, Copy, Default, Debug)]
pub struct Tracks<'a> {
data: &'a [u8], // the whole table
records: LazyArray16<'a, TrackTableRecord>,
sizes_count: u16,
}
impl<'a> Tracks<'a> {
/// Returns a track at index.
pub fn get(&self, index: u16) -> Option<Track<'a>> {
let record = self.records.get(index)?;
let mut s = Stream::new(self.data.get(record.offset.to_usize()..)?);
Some(Track {
value: record.value.0,
values: s.read_array16::<i16>(self.sizes_count)?,
name_index: record.name_id,
})
}
/// Returns the number of tracks.
pub fn len(&self) -> u16 {
self.records.len()
}
/// Checks if there are any tracks.
pub fn is_empty(&self) -> bool {
self.records.is_empty()
}
}
impl<'a> IntoIterator for Tracks<'a> {
type Item = Track<'a>;
type IntoIter = TracksIter<'a>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
TracksIter {
tracks: self,
index: 0,
}
}
}
/// An iterator over [`Tracks`].
#[allow(missing_debug_implementations)]
pub struct TracksIter<'a> {
tracks: Tracks<'a>,
index: u16,
}
impl<'a> Iterator for TracksIter<'a> {
type Item = Track<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.index < self.tracks.len() {
self.index += 1;
self.tracks.get(self.index - 1)
} else {
None
}
}
}
/// A track data.
#[derive(Clone, Copy, Default, Debug)]
pub struct TrackData<'a> {
/// A list of tracks.
pub tracks: Tracks<'a>,
/// A list of sizes.
pub sizes: LazyArray16<'a, Fixed>,
}
impl<'a> TrackData<'a> {
fn parse(offset: usize, data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new_at(data, offset)?;
let tracks_count = s.read::<u16>()?;
let sizes_count = s.read::<u16>()?;
let size_table_offset = s.read::<Offset32>()?; // Offset from start of the table.
let tracks = Tracks {
data,
records: s.read_array16::<TrackTableRecord>(tracks_count)?,
sizes_count,
};
// TODO: Isn't the size table is directly after the tracks table?!
// Why we need an offset then?
let sizes = {
let mut s = Stream::new_at(data, size_table_offset.to_usize())?;
s.read_array16::<Fixed>(sizes_count)?
};
Some(TrackData { tracks, sizes })
}
}
/// A [Tracking Table](
/// https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6trak.html).
#[derive(Clone, Copy, Debug)]
pub struct Table<'a> {
/// Horizontal track data.
pub horizontal: TrackData<'a>,
/// Vertical track data.
pub vertical: TrackData<'a>,
}
impl<'a> Table<'a> {
/// Parses a table from raw data.
pub fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let version = s.read::<u32>()?;
if version != 0x00010000 {
return None;
}
let format = s.read::<u16>()?;
if format != 0 {
return None;
}
let hor_offset = s.read::<Option<Offset16>>()?;
let ver_offset = s.read::<Option<Offset16>>()?;
s.skip::<u16>(); // reserved
let horizontal = if let Some(offset) = hor_offset {
TrackData::parse(offset.to_usize(), data)?
} else {
TrackData::default()
};
let vertical = if let Some(offset) = ver_offset {
TrackData::parse(offset.to_usize(), data)?
} else {
TrackData::default()
};
Some(Table {
horizontal,
vertical,
})
}
}

43
vendor/ttf-parser/src/tables/vhea.rs vendored Normal file
View File

@@ -0,0 +1,43 @@
//! A [Vertical Header Table](
//! https://docs.microsoft.com/en-us/typography/opentype/spec/vhea) implementation.
use crate::parser::Stream;
/// A [Vertical Header Table](https://docs.microsoft.com/en-us/typography/opentype/spec/vhea).
#[derive(Clone, Copy, Default, Debug)]
pub struct Table {
/// Face ascender.
pub ascender: i16,
/// Face descender.
pub descender: i16,
/// Face line gap.
pub line_gap: i16,
/// Number of metrics in the `vmtx` table.
pub number_of_metrics: u16,
}
impl Table {
/// Parses a table from raw data.
pub fn parse(data: &[u8]) -> Option<Self> {
// Do not check the exact length, because some fonts include
// padding in table's length in table records, which is incorrect.
if data.len() < 36 {
return None;
}
let mut s = Stream::new(data);
s.skip::<u32>(); // version
let ascender = s.read::<i16>()?;
let descender = s.read::<i16>()?;
let line_gap = s.read::<i16>()?;
s.advance(24);
let number_of_metrics = s.read::<u16>()?;
Some(Table {
ascender,
descender,
line_gap,
number_of_metrics,
})
}
}

65
vendor/ttf-parser/src/tables/vorg.rs vendored Normal file
View File

@@ -0,0 +1,65 @@
//! A [Vertical Origin Table](
//! https://docs.microsoft.com/en-us/typography/opentype/spec/vorg) implementation.
use crate::parser::{FromData, LazyArray16, Stream};
use crate::GlyphId;
/// Vertical origin metrics for the
/// [Vertical Origin Table](https://docs.microsoft.com/en-us/typography/opentype/spec/vorg).
#[derive(Clone, Copy, Debug)]
pub struct VerticalOriginMetrics {
/// Glyph ID.
pub glyph_id: GlyphId,
/// Y coordinate, in the font's design coordinate system, of the vertical origin.
pub y: i16,
}
impl FromData for VerticalOriginMetrics {
const SIZE: usize = 4;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(VerticalOriginMetrics {
glyph_id: s.read::<GlyphId>()?,
y: s.read::<i16>()?,
})
}
}
/// A [Vertical Origin Table](https://docs.microsoft.com/en-us/typography/opentype/spec/vorg).
#[derive(Clone, Copy, Debug)]
pub struct Table<'a> {
/// Default origin.
pub default_y: i16,
/// A list of metrics for each glyph.
///
/// Ordered by `glyph_id`.
pub metrics: LazyArray16<'a, VerticalOriginMetrics>,
}
impl<'a> Table<'a> {
/// Parses a table from raw data.
pub fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let version = s.read::<u32>()?;
if version != 0x00010000 {
return None;
}
let default_y = s.read::<i16>()?;
let count = s.read::<u16>()?;
let metrics = s.read_array16::<VerticalOriginMetrics>(count)?;
Some(Table { default_y, metrics })
}
/// Returns glyph's Y origin.
pub fn glyph_y_origin(&self, glyph_id: GlyphId) -> i16 {
self.metrics
.binary_search_by(|m| m.glyph_id.cmp(&glyph_id))
.map(|(_, m)| m.y)
.unwrap_or(self.default_y)
}
}