use crate::glyph_mapping::GlyphMapping;
use crate::number::q16;
use crate::{GlyphID, Result, Tape, Walue};
#[derive(Clone, Debug)]
pub struct GlyphData(pub Vec<Option<Glyph>>);
table! {
#[doc = "A glyph."]
pub Glyph { contour_count (i16), min_x (i16), min_y (i16), max_x (i16), max_y (i16), description (Description) |this, tape| {
tape.take_given(this.contour_count)
},
}
}
#[derive(Clone, Debug)]
pub enum Description {
Simple(SimpleDescription),
Composite(CompositeDescription),
}
table! {
@define
#[doc = "A simple-glyph description."]
pub SimpleDescription { end_points (Vec<u16> ), instruction_size (u16 ), instructions (Vec<u8> ), flags (Vec<PointFlags>), x (Vec<i16> ), y (Vec<i16> ), }
}
#[derive(Clone, Debug)]
pub struct CompositeDescription {
pub components: Vec<Component>,
pub instruction_size: u16,
pub instructions: Vec<u8>,
}
table! {
#[doc = "A component of a composite glyph."]
#[derive(Copy)]
pub Component { flags (ComponentFlags), glyph_id (GlyphID ), arguments (Arguments) |this, tape| { tape.take_given(this.flags)
},
options (Options) |this, tape| {
tape.take_given(this.flags)
},
}
}
flags! {
#[doc = "Point flags."]
pub PointFlags(u8) { 0b0000_0001 => is_on_curve,
0b0000_0010 => is_x_short,
0b0000_0100 => is_y_short,
0b0000_1000 => is_repeated,
0b0001_0000 => is_x_positive,
0b0001_0000 => is_x_same,
0b0010_0000 => is_y_positive,
0b0010_0000 => is_y_same,
0b0100_0000 => is_overlap_simple,
0b1000_0000 => is_invalid,
}
}
flags! {
@base
#[doc = "Component flags."]
pub ComponentFlags(u16) { 0b0000_0000_0000_0001 => are_arguments_words,
0b0000_0000_0000_0010 => are_arguments_xy,
0b0000_0000_0000_0100 => should_round_xy_to_grid,
0b0000_0000_0000_1000 => has_scalar_scale,
0b0000_0000_0010_0000 => has_more_components,
0b0000_0000_0100_0000 => has_vector_scale,
0b0000_0000_1000_0000 => has_matrix_scale,
0b0000_0001_0000_0000 => has_instructions,
0b0000_0010_0000_0000 => should_use_metrics,
0b0000_0100_0000_0000 => has_overlap,
0b0000_1000_0000_0000 => is_offset_scaled,
0b0001_0000_0000_0000 => is_offset_unscaled,
0b1110_0000_0001_0000 => is_invalid,
}
}
#[cfg(not(feature = "ignore-invalid-composite-glyph-flags"))]
flags!(@read pub ComponentFlags(u16));
#[cfg(feature = "ignore-invalid-composite-glyph-flags")]
impl crate::Value for ComponentFlags {
#[inline]
fn read<T: Tape>(tape: &mut T) -> Result<Self> {
Ok(ComponentFlags(tape.take()?))
}
}
#[derive(Clone, Copy, Debug)]
pub enum Arguments {
Offsets(i16, i16),
Indices(u16, u16),
}
#[derive(Clone, Copy, Debug, Default)]
pub enum Options {
#[default]
None,
Scalar(q16),
Vector(q16, q16),
Matrix(q16, q16, q16, q16),
}
dereference! { GlyphData::0 => [Option<Glyph>] }
impl<'l> Walue<'l> for GlyphData {
type Parameter = &'l GlyphMapping;
fn read<T: Tape>(tape: &mut T, mapping: &GlyphMapping) -> Result<Self> {
macro_rules! reject(
() => (
raise!("found a malformed glyph-to-location mapping")
);
($index:ident) => (
raise!("found a malformed glyph-to-location mapping at index {}", $index)
);
($index:ident, $error:ident) => (
raise!(@from $error, "found a malformed glyph-to-location mapping at index {}", $index)
);
);
let offsets: Vec<_> = match mapping {
GlyphMapping::HalfOffsets(ref offsets) => {
offsets.iter().map(|&offset| 2 * (offset as u64)).collect()
}
GlyphMapping::Offsets(ref offsets) => {
offsets.iter().map(|&offset| offset as u64).collect()
}
};
if offsets.is_empty() {
reject!();
}
let glyph_count = offsets.len() - 1;
let mut glyphs = Vec::with_capacity(glyph_count);
let position = tape.position()?;
for i in 0..glyph_count {
if offsets[i] > offsets[i + 1] {
reject!(i);
}
if offsets[i] == offsets[i + 1] {
glyphs.push(None);
continue;
}
tape.jump(position + offsets[i])?;
match tape.take() {
Ok(glyph) => glyphs.push(Some(glyph)),
Err(error) => reject!(i, error),
}
if tape.position()? > position + offsets[i + 1] {
reject!(i);
}
}
Ok(GlyphData(glyphs))
}
}
impl Default for Description {
#[inline]
fn default() -> Self {
Description::Simple(SimpleDescription::default())
}
}
impl Walue<'static> for Description {
type Parameter = i16;
fn read<T: Tape>(tape: &mut T, contour_count: i16) -> Result<Self> {
if contour_count < -1 {
raise!("found a malformed glyph");
}
if contour_count >= 0 {
return Ok(Description::Simple(
tape.take_given(contour_count as usize)?,
));
}
let mut components = vec![];
let mut component_count = 0;
let mut has_more_components = true;
let mut has_instructions = false;
while has_more_components {
components.push(tape.take::<Component>()?);
has_instructions |= components[component_count].flags.has_instructions();
has_more_components = components[component_count].flags.has_more_components();
component_count += 1;
}
let instruction_size = if has_instructions {
tape.take::<u16>()?
} else {
0
};
let instructions = tape.take_bytes(instruction_size as usize)?;
Ok(Description::Composite(CompositeDescription {
components,
instruction_size,
instructions,
}))
}
}
impl Walue<'static> for SimpleDescription {
type Parameter = usize;
fn read<T: Tape>(tape: &mut T, contour_count: usize) -> Result<Self> {
macro_rules! reject(() => (raise!("found a malformed glyph description")));
let end_points = tape.take_given::<Vec<u16>>(contour_count)?;
for i in 1..contour_count {
if end_points[i - 1] > end_points[i] {
reject!();
}
}
let point_count = end_points.last().map(|&i| i as usize + 1).unwrap_or(0);
let instruction_size = tape.take()?;
let instructions = tape.take_bytes(instruction_size as usize)?;
let mut flags = Vec::with_capacity(point_count);
let mut flag_count = 0;
while flag_count < point_count {
let flag = tape.take::<PointFlags>()?;
if flag.is_invalid() {
reject!();
}
let count = 1 + if flag.is_repeated() {
tape.take::<u8>()? as usize
} else {
0
};
if flag_count + count > point_count {
reject!();
}
for _ in 0..count {
flags.push(flag);
}
flag_count += count;
}
macro_rules! read_coordinates(
($is_short:ident, $is_positive:ident, $is_same:ident) => ({
let mut values = Vec::with_capacity(point_count);
for i in 0..point_count {
let value = if flags[i].$is_short() {
let value = tape.take::<u8>()? as i16;
if flags[i].$is_positive() { value } else { -value }
} else {
if flags[i].$is_same() { 0 } else { tape.take::<i16>()? }
};
values.push(value);
}
values
});
);
let x = read_coordinates!(is_x_short, is_x_positive, is_x_same);
let y = read_coordinates!(is_y_short, is_y_positive, is_y_same);
Ok(SimpleDescription {
end_points,
instruction_size,
instructions,
flags,
x,
y,
})
}
}
impl Default for Arguments {
#[inline]
fn default() -> Self {
Arguments::Offsets(0, 0)
}
}
impl Walue<'static> for Arguments {
type Parameter = ComponentFlags;
fn read<T: Tape>(tape: &mut T, flags: ComponentFlags) -> Result<Self> {
match (flags.are_arguments_words(), flags.are_arguments_xy()) {
(true, true) => {
let x = tape.take::<i16>()?;
let y = tape.take::<i16>()?;
Ok(Arguments::Offsets(x, y))
}
(false, true) => {
let x = tape.take::<i8>()? as i16;
let y = tape.take::<i8>()? as i16;
Ok(Arguments::Offsets(x, y))
}
(true, false) => {
let i = tape.take::<u16>()?;
let j = tape.take::<u16>()?;
Ok(Arguments::Indices(i, j))
}
(false, false) => {
let i = tape.take::<u8>()? as u16;
let j = tape.take::<u8>()? as u16;
Ok(Arguments::Indices(i, j))
}
}
}
}
impl Walue<'static> for Options {
type Parameter = ComponentFlags;
fn read<T: Tape>(tape: &mut T, flags: ComponentFlags) -> Result<Self> {
if flags.has_scalar_scale() {
Ok(Options::Scalar(tape.take()?))
} else if flags.has_vector_scale() {
Ok(Options::Vector(tape.take()?, tape.take()?))
} else if flags.has_matrix_scale() {
Ok(Options::Matrix(
tape.take()?,
tape.take()?,
tape.take()?,
tape.take()?,
))
} else {
Ok(Options::None)
}
}
}