use crate::{
offset::SerializeSubset,
offset_array::SubsetOffsetArray,
serialize::{SerializeErrorFlags, Serializer},
variations::DeltaSetIndexMapSerializePlan,
Plan, Subset, SubsetError, SubsetTable,
};
use fnv::FnvHashMap;
use fontcull_skrifa::raw::{tables::colr::Affine2x3, ResolveOffset};
use fontcull_write_fonts::{
read::{
collections::IntSet,
tables::{
colr::{
BaseGlyph, BaseGlyphList, BaseGlyphPaint, ClipBox, ClipBoxFormat1, ClipBoxFormat2,
ClipList, ColorLine, ColorStop, Colr, Layer, LayerList, Paint, PaintColrGlyph,
PaintColrLayers, PaintComposite, PaintGlyph, PaintLinearGradient,
PaintRadialGradient, PaintRotate, PaintRotateAroundCenter, PaintScale,
PaintScaleAroundCenter, PaintScaleUniform, PaintScaleUniformAroundCenter,
PaintSkew, PaintSkewAroundCenter, PaintSolid, PaintSweepGradient, PaintTransform,
PaintTranslate, PaintVarLinearGradient, PaintVarRadialGradient, PaintVarRotate,
PaintVarRotateAroundCenter, PaintVarScale, PaintVarScaleAroundCenter,
PaintVarScaleUniform, PaintVarScaleUniformAroundCenter, PaintVarSkew,
PaintVarSkewAroundCenter, PaintVarSolid, PaintVarSweepGradient, PaintVarTransform,
PaintVarTranslate, VarAffine2x3, VarColorLine, VarColorStop,
},
variations::NO_VARIATION_INDEX,
},
FontRef, TopLevelTable,
},
types::{GlyphId, Offset24, Offset32},
FontBuilder,
};
impl Subset for Colr<'_> {
fn subset(
&self,
plan: &Plan,
_font: &FontRef,
s: &mut Serializer,
_builder: &mut FontBuilder,
) -> Result<(), SubsetError> {
let base_glyph_list = self
.base_glyph_list()
.transpose()
.map_err(|_| SubsetError::SubsetTableError(Colr::TAG))?;
let subset_to_v0 = downgrade_to_v0(base_glyph_list.as_ref(), plan);
serialize_v0(self, plan, s, subset_to_v0)
.map_err(|_| SubsetError::SubsetTableError(Colr::TAG))?;
if subset_to_v0 {
return Ok(());
}
s.copy_assign(0, 1_u16);
if let Some(var_store) = self
.item_variation_store()
.transpose()
.map_err(|_| SubsetError::SubsetTableError(Colr::TAG))?
{
Offset32::serialize_subset(&var_store, s, plan, &plan.colr_varstore_inner_maps, 30)
.map_err(|_| SubsetError::SubsetTableError(Colr::TAG))?;
}
Offset32::serialize_subset(&base_glyph_list.unwrap(), s, plan, (), 14)
.map_err(|_| SubsetError::SubsetTableError(Colr::TAG))?;
if let Some(layer_list) = self
.layer_list()
.transpose()
.map_err(|_| SubsetError::SubsetTableError(Colr::TAG))?
{
match Offset32::serialize_subset(&layer_list, s, plan, (), 18) {
Ok(()) | Err(SerializeErrorFlags::SERIALIZE_ERROR_EMPTY) => (),
Err(_) => {
return Err(SubsetError::SubsetTableError(Colr::TAG));
}
}
}
if let Some(clip_list) = self
.clip_list()
.transpose()
.map_err(|_| SubsetError::SubsetTableError(Colr::TAG))?
{
match Offset32::serialize_subset(&clip_list, s, plan, (), 22) {
Ok(()) | Err(SerializeErrorFlags::SERIALIZE_ERROR_EMPTY) => (),
Err(_) => {
return Err(SubsetError::SubsetTableError(Colr::TAG));
}
}
}
if let Some(var_index_map) = self
.var_index_map()
.transpose()
.map_err(|_| SubsetError::SubsetTableError(Colr::TAG))?
{
if let Some(deltaset_index_map_subset_plan) =
create_deltaset_index_map_subset_plan(plan)
{
Offset32::serialize_subset(
&var_index_map,
s,
plan,
&deltaset_index_map_subset_plan,
26,
)
.map_err(|_| SubsetError::SubsetTableError(Colr::TAG))?;
}
}
Ok(())
}
}
fn serialize_v0(
colr: &Colr,
plan: &Plan,
s: &mut Serializer,
subset_to_v0: bool,
) -> Result<(), SerializeErrorFlags> {
let num_records = colr.num_base_glyph_records();
if num_records == 0 && subset_to_v0 {
return Err(SerializeErrorFlags::SERIALIZE_ERROR_EMPTY);
}
let base_glyph_records = colr
.base_glyph_records()
.transpose()
.map_err(|_| SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR)?;
s.allocate_size(14, false)?;
if !subset_to_v0 {
s.allocate_size(20, false)?;
}
if base_glyph_records.is_none() {
return Ok(());
}
let base_glyph_records = base_glyph_records.unwrap();
let num_bit_storage = 16 - num_records.leading_zeros() as usize;
let glyph_set = &plan.glyphset_colred;
let retained_record_idxes: Vec<usize> =
if num_records as usize > glyph_set.len() as usize * num_bit_storage {
glyph_set
.iter()
.filter_map(|g| {
base_glyph_records
.binary_search_by_key(&g.to_u32(), |record| record.glyph_id().to_u32())
.ok()
})
.collect()
} else {
base_glyph_records
.iter()
.enumerate()
.filter_map(|(idx, record)| {
if !glyph_set.contains(GlyphId::from(record.glyph_id())) {
None
} else {
Some(idx)
}
})
.collect()
};
if retained_record_idxes.is_empty() {
if subset_to_v0 {
return Err(SerializeErrorFlags::SERIALIZE_ERROR_EMPTY);
}
return Ok(());
}
let mut num_layers = 0;
Offset32::serialize_subset(
&base_glyph_records,
s,
plan,
(&retained_record_idxes, &mut num_layers),
4,
)?;
s.copy_assign(2, retained_record_idxes.len() as u16);
s.copy_assign(12, num_layers);
let layer_records = colr
.layer_records()
.transpose()
.map_err(|_| SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR)?
.unwrap();
Offset32::serialize_subset(
&layer_records,
s,
plan,
(base_glyph_records, &retained_record_idxes),
8,
)?;
Ok(())
}
impl<'a> SubsetTable<'a> for &[BaseGlyph] {
type ArgsForSubset = (&'a [usize], &'a mut u16);
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let (retained_record_idxes, num_layers) = args;
let glyph_map = &plan.glyph_map;
for idx in retained_record_idxes {
let record = self.get(*idx).unwrap();
let old_gid = GlyphId::from(record.glyph_id());
let Some(new_gid) = glyph_map.get(&old_gid) else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER));
};
s.embed(new_gid.to_u32() as u16)?;
s.embed(*num_layers)?;
let record_num_layers = record.num_layers();
s.embed(record_num_layers)?;
*num_layers += record_num_layers;
}
Ok(())
}
}
impl<'a> SubsetTable<'a> for &[Layer] {
type ArgsForSubset = (&'a [BaseGlyph], &'a [usize]);
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let (base_glyph_records, retained_record_idxes) = args;
let glyph_map = &plan.glyph_map;
let palettes_map = &plan.colr_palettes;
for idx in retained_record_idxes {
let record = base_glyph_records.get(*idx).unwrap();
let layer_idx = record.first_layer_index() as usize;
let record_num_layers = record.num_layers() as usize;
for i in layer_idx..layer_idx + record_num_layers {
let Some(layer_record) = self.get(i) else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER));
};
let old_gid = GlyphId::from(layer_record.glyph_id());
let Some(new_gid) = glyph_map.get(&old_gid) else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER));
};
let palette_idx = layer_record.palette_index();
let Some(new_palette_idx) = palettes_map.get(&palette_idx) else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER));
};
s.embed(new_gid.to_u32() as u16)?;
s.embed(*new_palette_idx)?;
}
}
Ok(())
}
}
impl SubsetTable<'_> for BaseGlyphList<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<Self::Output, SerializeErrorFlags> {
let num_pos = s.embed(0_u32)?;
let mut num = 0_u32;
for paint_record in self.base_glyph_paint_records() {
if !plan
.glyphset_colred
.contains(GlyphId::from(paint_record.glyph_id()))
{
continue;
}
paint_record.subset(plan, s, self)?;
num += 1;
}
s.copy_assign(num_pos, num);
Ok(())
}
}
impl<'a> SubsetTable<'a> for BaseGlyphPaint {
type ArgsForSubset = &'a BaseGlyphList<'a>;
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
base_glyph_list: &BaseGlyphList,
) -> Result<Self::Output, SerializeErrorFlags> {
let old_gid = GlyphId::from(self.glyph_id());
let Some(new_gid) = plan.glyph_map.get(&old_gid) else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER));
};
s.embed(new_gid.to_u32() as u16)?;
let offset_pos = s.embed(0_u32)?;
let Ok(paint) = self.paint(base_glyph_list.offset_data()) else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset32::serialize_subset(&paint, s, plan, (), offset_pos)
}
}
impl SubsetTable<'_> for LayerList<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<Self::Output, SerializeErrorFlags> {
let layers_map = &plan.colrv1_layers;
if layers_map.is_empty() {
return Err(SerializeErrorFlags::SERIALIZE_ERROR_EMPTY);
}
s.embed(layers_map.len() as u32)?;
let paint_offsets = self.paints();
let num_layers = self.num_layers();
for idx in 0..num_layers {
if !layers_map.contains_key(&idx) {
continue;
}
paint_offsets.subset_offset(idx as usize, s, plan, ())?;
}
Ok(())
}
}
impl SubsetTable<'_> for ClipList<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<Self::Output, SerializeErrorFlags> {
let glyph_set = &plan.glyphset_colred;
let glyph_map = &plan.glyph_map;
let retained_first_gid = glyph_set.first().unwrap().to_u32();
let retained_last_gid = glyph_set.last().unwrap().to_u32();
let mut new_gids_set = IntSet::empty();
let mut new_gids_offset_map = FnvHashMap::default();
for clip in self.clips() {
let start_gid = clip.start_glyph_id().to_u32();
let end_gid = clip.end_glyph_id().to_u32();
if end_gid < retained_first_gid || start_gid > retained_last_gid {
continue;
}
let offset = clip.clip_box_offset();
for gid in start_gid..=end_gid {
let g = GlyphId::from(gid);
if !glyph_set.contains(g) {
continue;
}
let Some(new_gid) = glyph_map.get(&g) else {
continue;
};
let new_gid = new_gid.to_u32() as u16;
new_gids_set.insert(new_gid);
new_gids_offset_map.insert(new_gid, offset);
}
}
if new_gids_set.is_empty() {
return Err(SerializeErrorFlags::SERIALIZE_ERROR_EMPTY);
}
s.embed(self.format())?;
let num_clips_pos = s.embed(0_u32)?;
let num_clips = serialize_clips(self, s, plan, &new_gids_set, &new_gids_offset_map)?;
s.copy_assign(num_clips_pos, num_clips);
Ok(())
}
}
fn serialize_clips(
clip_list: &ClipList,
s: &mut Serializer,
plan: &Plan,
gids_set: &IntSet<u16>,
gids_offset_map: &FnvHashMap<u16, Offset24>,
) -> Result<u32, SerializeErrorFlags> {
let mut count = 0;
let mut start_gid = gids_set.first().unwrap();
let mut prev_gid = start_gid;
let mut prev_offset = gids_offset_map.get(&start_gid).unwrap();
for g in gids_set.iter().skip(1) {
let offset = gids_offset_map.get(&g).unwrap();
if g == prev_gid + 1 && offset == prev_offset {
prev_gid = g;
continue;
}
let clip_box: ClipBox = prev_offset
.resolve(clip_list.offset_data())
.map_err(|_| SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR)?;
serialize_clip(s, plan, start_gid, prev_gid, &clip_box)?;
count += 1;
start_gid = g;
prev_gid = g;
prev_offset = offset;
}
let clip_box: ClipBox = prev_offset
.resolve(clip_list.offset_data())
.map_err(|_| SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR)?;
serialize_clip(s, plan, start_gid, prev_gid, &clip_box)?;
count += 1;
Ok(count)
}
fn serialize_clip(
s: &mut Serializer,
plan: &Plan,
start: u16,
end: u16,
clip_box: &ClipBox,
) -> Result<(), SerializeErrorFlags> {
s.embed(start)?;
s.embed(end)?;
let offset_pos = s.embed_bytes(&[0_u8; 3])?;
Offset24::serialize_subset(clip_box, s, plan, (), offset_pos)
}
impl SubsetTable<'_> for ClipBox<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
args: Self::ArgsForSubset,
) -> Result<Self::Output, SerializeErrorFlags> {
match self {
Self::Format1(item) => item.subset(plan, s, args),
Self::Format2(item) => item.subset(plan, s, args),
}
}
}
impl SubsetTable<'_> for ClipBoxFormat1<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
_plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<Self::Output, SerializeErrorFlags> {
s.embed_bytes(self.min_table_bytes()).map(|_| ())
}
}
impl SubsetTable<'_> for ClipBoxFormat2<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<Self::Output, SerializeErrorFlags> {
let start_pos = s.embed_bytes(self.min_table_bytes())?;
let varidx_base = self.var_index_base();
if varidx_base != NO_VARIATION_INDEX {
let Some((new_varidx, _)) = plan.colr_varidx_delta_map.get(&varidx_base) else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER));
};
s.copy_assign(
start_pos + self.shape().var_index_base_byte_range().start,
*new_varidx,
);
}
Ok(())
}
}
fn create_deltaset_index_map_subset_plan(plan: &Plan) -> Option<DeltaSetIndexMapSerializePlan<'_>> {
let deltaset_idx_varidx_map = &plan.colr_new_deltaset_idx_varidx_map;
let count = deltaset_idx_varidx_map.len();
if count == 0 {
return None;
}
let mut last_idx = count as u32 - 1;
let last_varidx = deltaset_idx_varidx_map.get(&last_idx).unwrap();
for i in (0..last_idx).rev() {
let var_idx = deltaset_idx_varidx_map.get(&i).unwrap();
if var_idx != last_varidx {
break;
}
last_idx = i;
}
let map_count = last_idx + 1;
let mut outer_bit_count = 1;
let mut inner_bit_count = 1;
for idx in 0..map_count {
let var_idx = deltaset_idx_varidx_map.get(&idx).unwrap();
let outer = var_idx >> 16;
let bit_count = 32 - outer.leading_zeros();
outer_bit_count = outer_bit_count.max(bit_count);
let inner = var_idx & 0xFFFF;
let bit_count = 32 - inner.leading_zeros();
inner_bit_count = inner_bit_count.max(bit_count);
}
Some(DeltaSetIndexMapSerializePlan::new(
outer_bit_count as u8,
inner_bit_count as u8,
&plan.colr_new_deltaset_idx_varidx_map,
map_count,
))
}
impl SubsetTable<'_> for ColorStop {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<Self::Output, SerializeErrorFlags> {
s.embed(self.stop_offset())?;
let palette_idx = self.palette_index();
let Some(new_idx) = plan.colr_palettes.get(&palette_idx) else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER));
};
s.embed(*new_idx)?;
s.embed(self.alpha()).map(|_| ())
}
}
impl SubsetTable<'_> for VarColorStop {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<Self::Output, SerializeErrorFlags> {
s.embed(self.stop_offset())?;
let palette_idx = self.palette_index();
let Some(new_idx) = plan.colr_palettes.get(&palette_idx) else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER));
};
s.embed(*new_idx)?;
s.embed(self.alpha())?;
let varidx_base = self.var_index_base();
if varidx_base != NO_VARIATION_INDEX {
let Some((new_varidx, _)) = plan.colr_varidx_delta_map.get(&varidx_base) else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER));
};
s.embed(*new_varidx)?;
}
s.embed(varidx_base).map(|_| ())
}
}
impl SubsetTable<'_> for ColorLine<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<Self::Output, SerializeErrorFlags> {
s.embed(self.extend())?;
s.embed(self.num_stops())?;
for stop in self.color_stops() {
stop.subset(plan, s, ())?;
}
Ok(())
}
}
impl SubsetTable<'_> for VarColorLine<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<Self::Output, SerializeErrorFlags> {
s.embed(self.extend())?;
s.embed(self.num_stops())?;
for stop in self.color_stops() {
stop.subset(plan, s, ())?;
}
Ok(())
}
}
impl SubsetTable<'_> for Paint<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
args: Self::ArgsForSubset,
) -> Result<Self::Output, SerializeErrorFlags> {
match self {
Self::ColrLayers(item) => item.subset(plan, s, args),
Self::Solid(item) => item.subset(plan, s, args),
Self::VarSolid(item) => item.subset(plan, s, args),
Self::LinearGradient(item) => item.subset(plan, s, args),
Self::VarLinearGradient(item) => item.subset(plan, s, args),
Self::RadialGradient(item) => item.subset(plan, s, args),
Self::VarRadialGradient(item) => item.subset(plan, s, args),
Self::SweepGradient(item) => item.subset(plan, s, args),
Self::VarSweepGradient(item) => item.subset(plan, s, args),
Self::Glyph(item) => item.subset(plan, s, args),
Self::ColrGlyph(item) => item.subset(plan, s, args),
Self::Transform(item) => item.subset(plan, s, args),
Self::VarTransform(item) => item.subset(plan, s, args),
Self::Translate(item) => item.subset(plan, s, args),
Self::VarTranslate(item) => item.subset(plan, s, args),
Self::Scale(item) => item.subset(plan, s, args),
Self::VarScale(item) => item.subset(plan, s, args),
Self::ScaleAroundCenter(item) => item.subset(plan, s, args),
Self::VarScaleAroundCenter(item) => item.subset(plan, s, args),
Self::ScaleUniform(item) => item.subset(plan, s, args),
Self::VarScaleUniform(item) => item.subset(plan, s, args),
Self::ScaleUniformAroundCenter(item) => item.subset(plan, s, args),
Self::VarScaleUniformAroundCenter(item) => item.subset(plan, s, args),
Self::Rotate(item) => item.subset(plan, s, args),
Self::VarRotate(item) => item.subset(plan, s, args),
Self::RotateAroundCenter(item) => item.subset(plan, s, args),
Self::VarRotateAroundCenter(item) => item.subset(plan, s, args),
Self::Skew(item) => item.subset(plan, s, args),
Self::VarSkew(item) => item.subset(plan, s, args),
Self::SkewAroundCenter(item) => item.subset(plan, s, args),
Self::VarSkewAroundCenter(item) => item.subset(plan, s, args),
Self::Composite(item) => item.subset(plan, s, args),
}
}
}
impl SubsetTable<'_> for PaintColrLayers<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let start_pos = s.embed_bytes(self.min_table_bytes())?;
let old_layer_idx = self.first_layer_index();
let Some(new_layer_idx) = plan.colrv1_layers.get(&old_layer_idx) else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER));
};
s.copy_assign(start_pos + 2, *new_layer_idx);
Ok(())
}
}
impl SubsetTable<'_> for PaintSolid<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let start_pos = s.embed_bytes(self.min_table_bytes())?;
let palette_idx = self.palette_index();
let Some(new_idx) = plan.colr_palettes.get(&palette_idx) else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER));
};
s.copy_assign(start_pos + 1, *new_idx);
Ok(())
}
}
impl SubsetTable<'_> for PaintVarSolid<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let start_pos = s.embed_bytes(self.min_table_bytes())?;
let palette_idx = self.palette_index();
let Some(new_idx) = plan.colr_palettes.get(&palette_idx) else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER));
};
s.copy_assign(start_pos + 1, *new_idx);
let varidx_base = self.var_index_base();
if varidx_base != NO_VARIATION_INDEX {
let Some((new_varidx, _)) = plan.colr_varidx_delta_map.get(&varidx_base) else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER));
};
s.copy_assign(start_pos + 5, *new_varidx);
}
Ok(())
}
}
impl SubsetTable<'_> for PaintLinearGradient<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let start_pos = s.embed_bytes(self.min_table_bytes())?;
let Ok(color_line) = self.color_line() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&color_line, s, plan, (), start_pos + 1)
}
}
impl SubsetTable<'_> for PaintVarLinearGradient<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let start_pos = s.embed_bytes(self.min_table_bytes())?;
let Ok(color_line) = self.color_line() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&color_line, s, plan, (), start_pos + 1)?;
let varidx_base = self.var_index_base();
if varidx_base != NO_VARIATION_INDEX {
let Some((new_varidx, _)) = plan.colr_varidx_delta_map.get(&varidx_base) else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER));
};
let pos = start_pos + self.shape().var_index_base_byte_range().start;
s.copy_assign(pos, *new_varidx);
}
Ok(())
}
}
impl SubsetTable<'_> for PaintRadialGradient<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let start_pos = s.embed_bytes(self.min_table_bytes())?;
let Ok(color_line) = self.color_line() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&color_line, s, plan, (), start_pos + 1)
}
}
impl SubsetTable<'_> for PaintVarRadialGradient<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let start_pos = s.embed_bytes(self.min_table_bytes())?;
let Ok(color_line) = self.color_line() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&color_line, s, plan, (), start_pos + 1)?;
let varidx_base = self.var_index_base();
if varidx_base != NO_VARIATION_INDEX {
let Some((new_varidx, _)) = plan.colr_varidx_delta_map.get(&varidx_base) else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER));
};
let pos = start_pos + self.shape().var_index_base_byte_range().start;
s.copy_assign(pos, *new_varidx);
}
Ok(())
}
}
impl SubsetTable<'_> for PaintSweepGradient<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let start_pos = s.embed_bytes(self.min_table_bytes())?;
let Ok(color_line) = self.color_line() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&color_line, s, plan, (), start_pos + 1)
}
}
impl SubsetTable<'_> for PaintVarSweepGradient<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let start_pos = s.embed_bytes(self.min_table_bytes())?;
let Ok(color_line) = self.color_line() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&color_line, s, plan, (), start_pos + 1)?;
let varidx_base = self.var_index_base();
if varidx_base != NO_VARIATION_INDEX {
let Some((new_varidx, _)) = plan.colr_varidx_delta_map.get(&varidx_base) else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER));
};
let pos = start_pos + self.shape().var_index_base_byte_range().start;
s.copy_assign(pos, *new_varidx);
}
Ok(())
}
}
impl SubsetTable<'_> for PaintGlyph<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
s.embed(self.format())?;
let offset_pos = s.embed_bytes(&[0_u8; 3])?;
let old_gid = GlyphId::from(self.glyph_id());
let Some(new_gid) = plan.glyph_map.get(&old_gid) else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER));
};
s.embed(new_gid.to_u32() as u16)?;
let Ok(paint) = self.paint() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&paint, s, plan, (), offset_pos)
}
}
impl SubsetTable<'_> for PaintColrGlyph<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
s.embed(self.format())?;
let old_gid = GlyphId::from(self.glyph_id());
let Some(new_gid) = plan.glyph_map.get(&old_gid) else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER));
};
s.embed(new_gid.to_u32() as u16).map(|_| ())
}
}
impl SubsetTable<'_> for Affine2x3<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
_plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
s.embed_bytes(self.min_table_bytes()).map(|_| ())
}
}
impl SubsetTable<'_> for VarAffine2x3<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let start_pos = s.embed_bytes(self.min_table_bytes())?;
let varidx_base = self.var_index_base();
if varidx_base != NO_VARIATION_INDEX {
let Some((new_varidx, _)) = plan.colr_varidx_delta_map.get(&varidx_base) else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER));
};
let pos = start_pos + self.shape().var_index_base_byte_range().start;
s.copy_assign(pos, *new_varidx);
}
Ok(())
}
}
impl SubsetTable<'_> for PaintTransform<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
s.embed(self.format())?;
let paint_pos = s.embed_bytes(&[0_u8; 3])?;
let transform_pos = s.embed_bytes(&[0_u8; 3])?;
let Ok(paint) = self.paint() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&paint, s, plan, (), paint_pos)?;
let Ok(affine) = self.transform() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&affine, s, plan, (), transform_pos)
}
}
impl SubsetTable<'_> for PaintVarTransform<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
s.embed(self.format())?;
let paint_pos = s.embed_bytes(&[0_u8; 3])?;
let transform_pos = s.embed_bytes(&[0_u8; 3])?;
let Ok(paint) = self.paint() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&paint, s, plan, (), paint_pos)?;
let Ok(affine) = self.transform() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&affine, s, plan, (), transform_pos)
}
}
impl SubsetTable<'_> for PaintTranslate<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let start_pos = s.embed_bytes(self.min_table_bytes())?;
let Ok(paint) = self.paint() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&paint, s, plan, (), start_pos + 1)
}
}
impl SubsetTable<'_> for PaintVarTranslate<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let start_pos = s.embed_bytes(self.min_table_bytes())?;
let Ok(paint) = self.paint() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&paint, s, plan, (), start_pos + 1)?;
let varidx_base = self.var_index_base();
if varidx_base != NO_VARIATION_INDEX {
let Some((new_varidx, _)) = plan.colr_varidx_delta_map.get(&varidx_base) else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER));
};
let pos = start_pos + self.shape().var_index_base_byte_range().start;
s.copy_assign(pos, *new_varidx);
}
Ok(())
}
}
impl SubsetTable<'_> for PaintScale<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let start_pos = s.embed_bytes(self.min_table_bytes())?;
let Ok(paint) = self.paint() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&paint, s, plan, (), start_pos + 1)
}
}
impl SubsetTable<'_> for PaintVarScale<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let start_pos = s.embed_bytes(self.min_table_bytes())?;
let Ok(paint) = self.paint() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&paint, s, plan, (), start_pos + 1)?;
let varidx_base = self.var_index_base();
if varidx_base != NO_VARIATION_INDEX {
let Some((new_varidx, _)) = plan.colr_varidx_delta_map.get(&varidx_base) else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER));
};
let pos = start_pos + self.shape().var_index_base_byte_range().start;
s.copy_assign(pos, *new_varidx);
}
Ok(())
}
}
impl SubsetTable<'_> for PaintScaleAroundCenter<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let start_pos = s.embed_bytes(self.min_table_bytes())?;
let Ok(paint) = self.paint() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&paint, s, plan, (), start_pos + 1)
}
}
impl SubsetTable<'_> for PaintVarScaleAroundCenter<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let start_pos = s.embed_bytes(self.min_table_bytes())?;
let Ok(paint) = self.paint() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&paint, s, plan, (), start_pos + 1)?;
let varidx_base = self.var_index_base();
if varidx_base != NO_VARIATION_INDEX {
let Some((new_varidx, _)) = plan.colr_varidx_delta_map.get(&varidx_base) else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER));
};
let pos = start_pos + self.shape().var_index_base_byte_range().start;
s.copy_assign(pos, *new_varidx);
}
Ok(())
}
}
impl SubsetTable<'_> for PaintScaleUniform<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let start_pos = s.embed_bytes(self.min_table_bytes())?;
let Ok(paint) = self.paint() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&paint, s, plan, (), start_pos + 1)
}
}
impl SubsetTable<'_> for PaintVarScaleUniform<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let start_pos = s.embed_bytes(self.min_table_bytes())?;
let Ok(paint) = self.paint() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&paint, s, plan, (), start_pos + 1)?;
let varidx_base = self.var_index_base();
if varidx_base != NO_VARIATION_INDEX {
let Some((new_varidx, _)) = plan.colr_varidx_delta_map.get(&varidx_base) else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER));
};
let pos = start_pos + self.shape().var_index_base_byte_range().start;
s.copy_assign(pos, *new_varidx);
}
Ok(())
}
}
impl SubsetTable<'_> for PaintScaleUniformAroundCenter<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let start_pos = s.embed_bytes(self.min_table_bytes())?;
let Ok(paint) = self.paint() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&paint, s, plan, (), start_pos + 1)
}
}
impl SubsetTable<'_> for PaintVarScaleUniformAroundCenter<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let start_pos = s.embed_bytes(self.min_table_bytes())?;
let Ok(paint) = self.paint() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&paint, s, plan, (), start_pos + 1)?;
let varidx_base = self.var_index_base();
if varidx_base != NO_VARIATION_INDEX {
let Some((new_varidx, _)) = plan.colr_varidx_delta_map.get(&varidx_base) else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER));
};
let pos = start_pos + self.shape().var_index_base_byte_range().start;
s.copy_assign(pos, *new_varidx);
}
Ok(())
}
}
impl SubsetTable<'_> for PaintRotate<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let start_pos = s.embed_bytes(self.min_table_bytes())?;
let Ok(paint) = self.paint() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&paint, s, plan, (), start_pos + 1)
}
}
impl SubsetTable<'_> for PaintVarRotate<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let start_pos = s.embed_bytes(self.min_table_bytes())?;
let Ok(paint) = self.paint() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&paint, s, plan, (), start_pos + 1)?;
let varidx_base = self.var_index_base();
if varidx_base != NO_VARIATION_INDEX {
let Some((new_varidx, _)) = plan.colr_varidx_delta_map.get(&varidx_base) else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER));
};
let pos = start_pos + self.shape().var_index_base_byte_range().start;
s.copy_assign(pos, *new_varidx);
}
Ok(())
}
}
impl SubsetTable<'_> for PaintRotateAroundCenter<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let start_pos = s.embed_bytes(self.min_table_bytes())?;
let Ok(paint) = self.paint() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&paint, s, plan, (), start_pos + 1)
}
}
impl SubsetTable<'_> for PaintVarRotateAroundCenter<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let start_pos = s.embed_bytes(self.min_table_bytes())?;
let Ok(paint) = self.paint() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&paint, s, plan, (), start_pos + 1)?;
let varidx_base = self.var_index_base();
if varidx_base != NO_VARIATION_INDEX {
let Some((new_varidx, _)) = plan.colr_varidx_delta_map.get(&varidx_base) else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER));
};
let pos = start_pos + self.shape().var_index_base_byte_range().start;
s.copy_assign(pos, *new_varidx);
}
Ok(())
}
}
impl SubsetTable<'_> for PaintSkew<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let start_pos = s.embed_bytes(self.min_table_bytes())?;
let Ok(paint) = self.paint() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&paint, s, plan, (), start_pos + 1)
}
}
impl SubsetTable<'_> for PaintVarSkew<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let start_pos = s.embed_bytes(self.min_table_bytes())?;
let Ok(paint) = self.paint() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&paint, s, plan, (), start_pos + 1)?;
let varidx_base = self.var_index_base();
if varidx_base != NO_VARIATION_INDEX {
let Some((new_varidx, _)) = plan.colr_varidx_delta_map.get(&varidx_base) else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER));
};
let pos = start_pos + self.shape().var_index_base_byte_range().start;
s.copy_assign(pos, *new_varidx);
}
Ok(())
}
}
impl SubsetTable<'_> for PaintSkewAroundCenter<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let start_pos = s.embed_bytes(self.min_table_bytes())?;
let Ok(paint) = self.paint() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&paint, s, plan, (), start_pos + 1)
}
}
impl SubsetTable<'_> for PaintVarSkewAroundCenter<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
let start_pos = s.embed_bytes(self.min_table_bytes())?;
let Ok(paint) = self.paint() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&paint, s, plan, (), start_pos + 1)?;
let varidx_base = self.var_index_base();
if varidx_base != NO_VARIATION_INDEX {
let Some((new_varidx, _)) = plan.colr_varidx_delta_map.get(&varidx_base) else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_OTHER));
};
let pos = start_pos + self.shape().var_index_base_byte_range().start;
s.copy_assign(pos, *new_varidx);
}
Ok(())
}
}
impl SubsetTable<'_> for PaintComposite<'_> {
type ArgsForSubset = ();
type Output = ();
fn subset(
&self,
plan: &Plan,
s: &mut Serializer,
_args: Self::ArgsForSubset,
) -> Result<(), SerializeErrorFlags> {
s.embed(self.format())?;
let src_paint_pos = s.embed_bytes(&[0_u8; 3])?;
s.embed(self.composite_mode())?;
let backdrop_paint_pos = s.embed_bytes(&[0_u8; 3])?;
let Ok(src_paint) = self.source_paint() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&src_paint, s, plan, (), src_paint_pos)?;
let Ok(backdrop_paint) = self.backdrop_paint() else {
return Err(s.set_err(SerializeErrorFlags::SERIALIZE_ERROR_READ_ERROR));
};
Offset24::serialize_subset(&backdrop_paint, s, plan, (), backdrop_paint_pos)
}
}
fn downgrade_to_v0(base_glyph_list: Option<&BaseGlyphList>, plan: &Plan) -> bool {
if base_glyph_list.is_none() {
return true;
}
for paint_record in base_glyph_list.unwrap().base_glyph_paint_records() {
if plan
.glyphset_colred
.contains(GlyphId::from(paint_record.glyph_id()))
{
return false;
}
}
true
}
#[cfg(test)]
mod test {
use super::*;
use fontcull_write_fonts::{read::TableProvider, types::GlyphId};
#[test]
fn test_subset_colr_retain_all() {
let ttf: &[u8] = include_bytes!("../test-data/fonts/TwemojiMozilla.subset.ttf");
let font = FontRef::new(ttf).unwrap();
let colr = font.colr().unwrap();
let mut builder = FontBuilder::new();
let mut plan = Plan::default();
plan.glyphset_colred
.insert_range(GlyphId::NOTDEF..=GlyphId::from(6_u32));
plan.glyph_map.insert(GlyphId::NOTDEF, GlyphId::NOTDEF);
plan.glyph_map
.insert(GlyphId::from(1_u32), GlyphId::from(1_u32));
plan.glyph_map
.insert(GlyphId::from(2_u32), GlyphId::from(2_u32));
plan.glyph_map
.insert(GlyphId::from(3_u32), GlyphId::from(3_u32));
plan.glyph_map
.insert(GlyphId::from(4_u32), GlyphId::from(4_u32));
plan.glyph_map
.insert(GlyphId::from(5_u32), GlyphId::from(5_u32));
plan.glyph_map
.insert(GlyphId::from(6_u32), GlyphId::from(6_u32));
plan.colr_palettes.insert(2, 0);
plan.colr_palettes.insert(11, 1);
let mut s = Serializer::new(1024);
assert_eq!(s.start_serialize(), Ok(()));
let ret = colr.subset(&plan, &font, &mut s, &mut builder);
assert!(ret.is_ok());
assert!(!s.in_error());
s.end_serialize();
let subsetted_data = s.copy_bytes();
let expected_data: [u8; 42] = [
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x04,
0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06,
0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02,
];
assert_eq!(subsetted_data, expected_data);
}
#[test]
fn test_subset_colr_keep_one_colr_glyph() {
let ttf: &[u8] = include_bytes!("../test-data/fonts/TwemojiMozilla.subset.ttf");
let font = FontRef::new(ttf).unwrap();
let colr = font.colr().unwrap();
let mut builder = FontBuilder::new();
let mut plan = Plan::default();
plan.glyphset_colred.insert(GlyphId::NOTDEF);
plan.glyphset_colred.insert(GlyphId::from(2_u32));
plan.glyphset_colred.insert(GlyphId::from(4_u32));
plan.glyphset_colred.insert(GlyphId::from(5_u32));
plan.glyph_map.insert(GlyphId::NOTDEF, GlyphId::NOTDEF);
plan.glyph_map
.insert(GlyphId::from(2_u32), GlyphId::from(1_u32));
plan.glyph_map
.insert(GlyphId::from(4_u32), GlyphId::from(2_u32));
plan.glyph_map
.insert(GlyphId::from(5_u32), GlyphId::from(3_u32));
plan.colr_palettes.insert(2, 0);
plan.colr_palettes.insert(11, 1);
let mut s = Serializer::new(1024);
assert_eq!(s.start_serialize(), Ok(()));
let ret = colr.subset(&plan, &font, &mut s, &mut builder);
assert!(ret.is_ok());
assert!(!s.in_error());
s.end_serialize();
let subsetted_data = s.copy_bytes();
let expected_data: [u8; 28] = [
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x02,
0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
];
assert_eq!(subsetted_data, expected_data);
}
#[test]
fn test_subset_colr_keep_mixed_glyph() {
let ttf: &[u8] = include_bytes!("../test-data/fonts/TwemojiMozilla.subset.ttf");
let font = FontRef::new(ttf).unwrap();
let colr = font.colr().unwrap();
let mut builder = FontBuilder::new();
let mut plan = Plan::default();
plan.glyphset_colred.insert(GlyphId::NOTDEF);
plan.glyphset_colred.insert(GlyphId::from(1_u32));
plan.glyphset_colred.insert(GlyphId::from(3_u32));
plan.glyphset_colred.insert(GlyphId::from(4_u32));
plan.glyphset_colred.insert(GlyphId::from(6_u32));
plan.glyph_map.insert(GlyphId::NOTDEF, GlyphId::NOTDEF);
plan.glyph_map
.insert(GlyphId::from(1_u32), GlyphId::from(1_u32));
plan.glyph_map
.insert(GlyphId::from(3_u32), GlyphId::from(2_u32));
plan.glyph_map
.insert(GlyphId::from(4_u32), GlyphId::from(3_u32));
plan.glyph_map
.insert(GlyphId::from(6_u32), GlyphId::from(4_u32));
plan.colr_palettes.insert(2, 0);
plan.colr_palettes.insert(11, 1);
let mut s = Serializer::new(1024);
assert_eq!(s.start_serialize(), Ok(()));
let ret = colr.subset(&plan, &font, &mut s, &mut builder);
assert!(ret.is_ok());
assert!(!s.in_error());
s.end_serialize();
let subsetted_data = s.copy_bytes();
let expected_data: [u8; 28] = [
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x02,
0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
];
assert_eq!(subsetted_data, expected_data);
}
#[test]
fn test_subset_colr_keep_no_colr_glyph() {
let ttf: &[u8] = include_bytes!("../test-data/fonts/TwemojiMozilla.subset.ttf");
let font = FontRef::new(ttf).unwrap();
let colr = font.colr().unwrap();
let mut builder = FontBuilder::new();
let mut plan = Plan::default();
plan.glyphset_colred.insert(GlyphId::NOTDEF);
plan.glyphset_colred.insert(GlyphId::from(1_u32));
plan.glyph_map.insert(GlyphId::NOTDEF, GlyphId::NOTDEF);
plan.glyph_map
.insert(GlyphId::from(1_u32), GlyphId::from(1_u32));
let mut s = Serializer::new(1024);
assert_eq!(s.start_serialize(), Ok(()));
let ret = colr.subset(&plan, &font, &mut s, &mut builder);
assert!(ret.is_err());
assert!(!s.in_error());
s.end_serialize();
}
}