use crate::glyf::{glyf, Glyph};
use crate::otvar::iup::optimize_deltas;
use crate::otvar::*;
use counter::Counter;
use otspec::types::*;
use otspec::{DeserializationError, Deserializer, ReaderContext, SerializationError, Serialize};
use otspec_macros::tables;
use std::convert::TryInto;
#[cfg(feature = "rayon")]
use rayon::prelude::*;
type Coords = Vec<(int16, int16)>;
pub(crate) type CoordsAndEndsVec = Vec<(Coords, Vec<usize>)>;
tables!( gvarcore {
uint16 majorVersion
uint16 minorVersion
uint16 axisCount
uint16 sharedTupleCount
u32 sharedTuplesOffset
uint16 glyphCount
uint16 flags
u32 glyphVariationDataArrayOffset
}
);
#[derive(Debug, PartialEq, Clone)]
pub struct DeltaSet {
pub peak: Tuple,
pub start: Tuple,
pub end: Tuple,
pub deltas: Vec<(i16, i16)>,
}
impl DeltaSet {
fn to_tuple_variation(
&self,
shared_tuples: &[Vec<u8>],
original_glyph: Option<&Glyph>,
) -> TupleVariation {
let mut serialized_peak: Vec<u8> = vec![];
for p in &self.peak {
F2DOT14::from(*p).to_bytes(&mut serialized_peak).unwrap();
}
let index = shared_tuples.iter().position(|t| t == &serialized_peak);
let mut flags = TupleIndexFlags::empty();
let shared_tuple_index: uint16;
if let Some(sti) = index {
shared_tuple_index = sti as u16;
} else {
shared_tuple_index = 0;
flags |= TupleIndexFlags::EMBEDDED_PEAK_TUPLE;
}
if self.peak != self.start || self.peak != self.end {
flags |= TupleIndexFlags::INTERMEDIATE_REGION;
}
let tvh = TupleVariationHeader {
size: 0, flags,
sharedTupleIndex: shared_tuple_index,
peakTuple: if flags.contains(TupleIndexFlags::EMBEDDED_PEAK_TUPLE) {
Some(self.peak.clone())
} else {
None
},
startTuple: if flags.contains(TupleIndexFlags::INTERMEDIATE_REGION) {
Some(self.start.clone())
} else {
None
},
endTuple: if flags.contains(TupleIndexFlags::INTERMEDIATE_REGION) {
Some(self.end.clone())
} else {
None
},
};
let deltas: Vec<Option<Delta>> = self
.deltas
.iter()
.map(|(x, y)| Some(Delta::Delta2D((*x, *y))))
.collect();
if let Some(glyph) = original_glyph {
let optimized_deltas = optimize_deltas(deltas.clone(), &glyph);
if optimized_deltas.iter().flatten().count() == 0 {
return TupleVariation(tvh, deltas);
}
let deltas_copy = deltas.clone();
let tv_unoptimized = TupleVariation(tvh.clone(), deltas_copy);
let original_length = otspec::ser::to_bytes(&TupleVariationStore(vec![tv_unoptimized]))
.unwrap()
.len();
let optimized_length =
otspec::ser::to_bytes(&TupleVariationStore(vec![TupleVariation(
tvh.clone(),
optimized_deltas.clone(),
)]))
.unwrap()
.len();
if optimized_length < original_length {
return TupleVariation(tvh, optimized_deltas);
} else {
return TupleVariation(tvh, deltas);
}
}
TupleVariation(tvh, deltas)
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct GlyphVariationData {
pub deltasets: Vec<DeltaSet>,
}
#[derive(Debug, PartialEq, Clone)]
#[allow(non_camel_case_types)]
pub struct gvar {
pub variations: Vec<Option<GlyphVariationData>>,
}
pub fn from_bytes(
s: &[u8],
coords_and_ends: CoordsAndEndsVec,
) -> Result<gvar, DeserializationError> {
let mut c = ReaderContext::new(s.to_vec());
c.push();
let core: gvarcore = c.de()?;
let offset_count = (core.glyphCount + 1) as usize;
let data_offsets: Vec<u32> = if core.flags & 0x1 == 0 {
let u16_and_halved: Vec<u16> = c.de_counted(offset_count)?;
u16_and_halved.iter().map(|x| (x * 2).into()).collect()
} else {
c.de_counted(offset_count)?
};
let axis_count = core.axisCount as usize;
let mut shared_tuples: Vec<Tuple> = Vec::with_capacity(core.sharedTupleCount as usize);
c.ptr = c.top_of_table() + (core.sharedTuplesOffset as usize);
for _ in 0..core.sharedTupleCount + 1 {
let tuple: Vec<F2DOT14> = c.de_counted(axis_count)?;
let tuple_f32: Vec<f32> = tuple.iter().map(|t| (*t).into()).collect();
shared_tuples.push(tuple_f32);
}
let mut glyph_variations = vec![];
for i in 0..(core.glyphCount as usize) {
let offset: usize = (data_offsets[i] + (core.glyphVariationDataArrayOffset))
.try_into()
.unwrap();
let next_offset: usize = (data_offsets[(i + 1) as usize]
+ (core.glyphVariationDataArrayOffset))
.try_into()
.unwrap();
let length = next_offset - offset;
if length == 0 {
glyph_variations.push(None);
} else {
let mut deltasets: Vec<DeltaSet> = vec![];
c.ptr = c.top_of_table() + offset;
let tvs = TupleVariationStore::from_bytes(
&mut c,
axis_count.try_into().unwrap(),
true,
coords_and_ends[i].0.len() as u16,
)?;
for tvh in tvs.0 {
let deltas = tvh.iup_delta(&coords_and_ends[i].0, &coords_and_ends[i].1);
let index = tvh.0.sharedTupleIndex as usize;
if index > shared_tuples.len() {
return Err(DeserializationError(format!(
"Invalid shared tuple index {:}",
index
)));
}
let peak_tuple = tvh
.0
.peakTuple
.unwrap_or_else(|| shared_tuples[index].clone());
let start_tuple = tvh.0.startTuple.unwrap_or_else(|| peak_tuple.clone());
let end_tuple = tvh.0.endTuple.unwrap_or_else(|| peak_tuple.clone());
deltasets.push(DeltaSet {
deltas,
peak: peak_tuple,
end: end_tuple,
start: start_tuple,
})
}
glyph_variations.push(Some(GlyphVariationData { deltasets }));
}
}
Ok(gvar {
variations: glyph_variations,
})
}
impl gvar {
pub fn to_bytes(&self, glyf: Option<&glyf>) -> Vec<u8> {
let mut out: Vec<u8> = vec![];
let mut shared_tuple_counter: Counter<Vec<u8>> = Counter::new();
let mut axis_count: uint16 = 0;
for var in self.variations.iter().flatten() {
for ds in &var.deltasets {
axis_count = ds.peak.len() as uint16;
let mut tuple: Vec<u8> = vec![];
for t in &ds.peak {
F2DOT14::from(*t).to_bytes(&mut tuple).unwrap();
}
shared_tuple_counter[&tuple] += 1;
}
}
let most_common_tuples: Vec<(Vec<u8>, usize)> = shared_tuple_counter.most_common();
if most_common_tuples.is_empty() {
panic!("Some more sensible error checking here for null case");
}
let shared_tuple_count = most_common_tuples.len() as u16;
let flags = 1;
let mut glyph_variation_data_offsets: Vec<u8> = vec![];
let mut shared_tuples = vec![];
let mut serialized_tuples = vec![];
let mut serialized_tvs = vec![];
for (a, _) in most_common_tuples {
serialized_tuples.extend(otspec::ser::to_bytes(&a).unwrap());
shared_tuples.push(a);
}
for (ix, var) in self.variations.iter().enumerate() {
if flags != 0 {
glyph_variation_data_offsets
.extend(&otspec::ser::to_bytes(&(serialized_tvs.len() as u32)).unwrap());
} else {
glyph_variation_data_offsets
.extend(&otspec::ser::to_bytes(&(serialized_tvs.len() as u16 / 2)).unwrap());
}
if let Some(var) = var {
let maybe_glyph = glyf.map(|g| &g.glyphs[ix]);
#[cfg(feature = "rayon")]
let tuple_variations = var
.deltasets
.par_iter()
.map(|ds| ds.to_tuple_variation(&shared_tuples, maybe_glyph))
.filter(|tv| tv.has_effect())
.collect();
#[cfg(not(feature = "rayon"))]
let tuple_variations = var
.deltasets
.iter()
.map(|ds| ds.to_tuple_variation(&shared_tuples, maybe_glyph))
.filter(|tv| tv.has_effect())
.collect();
let tvs = TupleVariationStore(tuple_variations);
serialized_tvs.extend(otspec::ser::to_bytes(&tvs).unwrap());
if (serialized_tvs.len() % 2) != 0 {
serialized_tvs.push(0);
}
}
}
if flags != 0 {
glyph_variation_data_offsets
.extend(&otspec::ser::to_bytes(&(serialized_tvs.len() as u32)).unwrap());
} else {
glyph_variation_data_offsets
.extend(&otspec::ser::to_bytes(&(serialized_tvs.len() as u16 / 2)).unwrap());
}
out.extend(
otspec::ser::to_bytes(&gvarcore {
majorVersion: 1,
minorVersion: 0,
axisCount: axis_count,
sharedTupleCount: shared_tuple_count,
sharedTuplesOffset: 20 + glyph_variation_data_offsets.len() as u32,
glyphCount: self.variations.len() as u16,
flags,
glyphVariationDataArrayOffset: 20
+ glyph_variation_data_offsets.len() as u32
+ serialized_tuples.len() as u32,
})
.unwrap(),
);
out.extend(glyph_variation_data_offsets);
out.extend(serialized_tuples);
out.extend(serialized_tvs);
out
}
}
impl Serialize for gvar {
fn to_bytes(&self, _data: &mut Vec<u8>) -> Result<(), SerializationError> {
panic!("Don't call this serializer, call the one in Font instead")
}
}
#[cfg(test)]
mod tests {
use crate::gvar;
use crate::gvar::GlyphVariationData;
#[test]
fn gvar_de() {
let binary_gvar = vec![
0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d,
0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x80, 0x02, 0x00, 0x0c,
0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x86, 0x02, 0xd2, 0xd2, 0x2e,
0x83, 0x02, 0x52, 0xae, 0xf7, 0x83, 0x86, 0x00, 0x80, 0x03, 0x00, 0x14, 0x00, 0x0a,
0x20, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x07, 0x80, 0x00, 0x40, 0x00, 0x40, 0x00,
0x00, 0x02, 0x01, 0x01, 0x02, 0x01, 0x26, 0xda, 0x01, 0x83, 0x7d, 0x03, 0x26, 0x26,
0xda, 0xda, 0x83, 0x87, 0x03, 0x13, 0x13, 0xed, 0xed, 0x83, 0x87, 0x00,
];
let deserialized: gvar::gvar = gvar::from_bytes(
&binary_gvar,
vec![
(vec![], vec![]), (vec![], vec![]), (
vec![
(437, 125),
(109, 125),
(254, 308),
(0, 0),
(0, 0),
(0, 0),
(0, 0),
],
vec![2, 3, 4, 5, 6],
),
(
vec![
(261, 611),
(261, 113),
(108, 113),
(108, 611),
(0, 0),
(0, 0),
(0, 0),
(0, 0),
],
vec![3, 4, 5, 6, 7],
),
],
)
.unwrap();
let variations = &deserialized.variations;
assert_eq!(variations[0], None);
assert_eq!(variations[1], None);
assert_eq!(
variations[2],
Some(GlyphVariationData {
deltasets: vec![
gvar::DeltaSet {
peak: vec![1.0, 0.0],
start: vec![1.0, 0.0],
end: vec![1.0, 0.0],
deltas: vec![(0, -46), (0, -46), (0, 46), (0, 0), (0, 0), (0, 0), (0, 0)]
},
gvar::DeltaSet {
peak: vec![0.0, 1.0],
start: vec![0.0, 1.0],
end: vec![0.0, 1.0],
deltas: vec![(82, 0), (-82, 0), (-9, 0), (0, 0), (0, 0), (0, 0), (0, 0)]
}
]
})
);
assert_eq!(
variations[3], Some(GlyphVariationData {
deltasets: vec![
gvar::DeltaSet {
peak: vec![1.0, 0.0],
start: vec![1.0, 0.0],
end: vec![1.0, 0.0],
deltas: vec![
(38, 125), (38, -125), (-38, -125), (-38, 125), (0, 0),
(0, 0),
(0, 0),
(0, 0)
]
},
gvar::DeltaSet {
peak: vec![0.0, 1.0],
start: vec![0.0, 1.0],
end: vec![0.0, 1.0],
deltas: vec![
(38, 0),
(38, 0),
(-38, 0),
(-38, 0),
(0, 0),
(0, 0),
(0, 0),
(0, 0)
]
},
gvar::DeltaSet {
peak: vec![1.0, 1.0],
start: vec![1.0, 1.0],
end: vec![1.0, 1.0],
deltas: vec![
(19, 0),
(19, 0),
(-19, 0),
(-19, 0),
(0, 0),
(0, 0),
(0, 0),
(0, 0)
]
}
]
})
);
}
#[test]
fn gvar_ser() {
let binary_gvar = vec![
0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d,
0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x80, 0x02, 0x00, 0x0c,
0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x86, 0x02, 0xd2, 0xd2, 0x2e,
0x83, 0x02, 0x52, 0xae, 0xf7, 0x83, 0x86, 0x00, 0x80, 0x03, 0x00, 0x14, 0x00, 0x0a,
0x20, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x07, 0x80, 0x00, 0x40, 0x00, 0x40, 0x00,
0x00, 0x02, 0x01, 0x01, 0x02, 0x01, 0x26, 0xda, 0x01, 0x83, 0x7d, 0x03, 0x26, 0x26,
0xda, 0xda, 0x83, 0x87, 0x03, 0x13, 0x13, 0xed, 0xed, 0x83, 0x87, 0x00,
];
let points = vec![
(vec![], vec![]), (vec![], vec![]), (
vec![
(437, 125),
(109, 125),
(254, 308),
(0, 0),
(0, 0),
(0, 0),
(0, 0),
],
vec![2, 3, 4, 5, 6],
),
(
vec![
(261, 611),
(261, 113),
(108, 113),
(108, 611),
(0, 0),
(0, 0),
(0, 0),
(0, 0),
],
vec![3, 4, 5, 6, 7],
),
];
let deserialized: gvar::gvar = gvar::from_bytes(&binary_gvar, points.clone()).unwrap();
let serialized = deserialized.to_bytes(None);
let re_de: gvar::gvar = gvar::from_bytes(&serialized, points).unwrap();
assert_eq!(re_de, deserialized);
}
}