[subset] subset both CPAL and COLRv1

This commit is contained in:
Qunxin Liu 2021-05-11 11:44:32 -07:00 committed by Garret Rieger
parent 466e1fdf5d
commit f739e1dc6a
60 changed files with 241 additions and 16 deletions

View File

@ -185,7 +185,7 @@ struct ColorIndex
TRACE_SUBSET (this);
auto *out = c->serializer->embed (*this);
if (unlikely (!out)) return_trace (false);
return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colrv1_palettes->get (paletteIndex),
return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes->get (paletteIndex),
HB_SERIALIZE_ERROR_INT_OVERFLOW));
}
@ -807,7 +807,7 @@ struct BaseGlyphV1List : SortedArray32Of<BaseGlyphV1Record>
else return_trace (false);
}
return_trace (true);
return_trace (out->len != 0);
}
};
@ -822,9 +822,12 @@ struct LayerV1List : Array32OfOffset32To<Paint>
auto *out = c->serializer->start_embed (this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
for (const auto& offset : as_array ()) {
for (const auto& _ : + hb_enumerate (*this)
| hb_filter (c->plan->colrv1_layers, hb_first))
{
auto *o = out->serialize_append (c->serializer);
if (unlikely (!o) || !o->serialize_subset (c, offset, this))
if (unlikely (!o) || !o->serialize_subset (c, _.second, this))
return_trace (false);
}
return_trace (true);
@ -878,6 +881,10 @@ struct COLR
hb_set_t *related_ids /* OUT */) const
{ colr->closure_glyphs (glyph, related_ids); }
void closure_V0palette_indices (const hb_set_t *glyphs,
hb_set_t *palettes /* OUT */) const
{ colr->closure_V0palette_indices (glyphs, palettes); }
void closure_forV1 (hb_set_t *glyphset,
hb_set_t *layer_indices,
hb_set_t *palette_indices) const
@ -899,6 +906,23 @@ struct COLR
related_ids->add_array (&glyph_layers[0].glyphId, glyph_layers.length, LayerRecord::min_size);
}
void closure_V0palette_indices (const hb_set_t *glyphs,
hb_set_t *palettes /* OUT */) const
{
if (!numBaseGlyphs || !numLayers) return;
hb_array_t<const BaseGlyphRecord> baseGlyphs = (this+baseGlyphsZ).as_array (numBaseGlyphs);
hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers);
for (const BaseGlyphRecord record : baseGlyphs)
{
if (!glyphs->has (record.glyphId)) continue;
hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx,
record.numLayers);
for (const LayerRecord layer : glyph_layers)
palettes->add (layer.colorIdx);
}
}
void closure_forV1 (hb_set_t *glyphset,
hb_set_t *layer_indices,
hb_set_t *palette_indices) const
@ -941,10 +965,10 @@ struct COLR
template<typename BaseIterator, typename LayerIterator,
hb_requires (hb_is_iterator (BaseIterator)),
hb_requires (hb_is_iterator (LayerIterator))>
bool serialize (hb_serialize_context_t *c,
unsigned version,
BaseIterator base_it,
LayerIterator layer_it)
bool serialize_V0 (hb_serialize_context_t *c,
unsigned version,
BaseIterator base_it,
LayerIterator layer_it)
{
TRACE_SERIALIZE (this);
if (unlikely (base_it.len () != layer_it.len ()))
@ -954,6 +978,12 @@ struct COLR
this->version = version;
numLayers = 0;
numBaseGlyphs = base_it.len ();
if (base_it.len () == 0)
{
baseGlyphsZ = 0;
layersZ = 0;
return_trace (true);
}
baseGlyphsZ = COLR::min_size;
layersZ = COLR::min_size + numBaseGlyphs * BaseGlyphRecord::min_size;
@ -1036,6 +1066,7 @@ struct COLR
if (unlikely (!c->plan->new_gid_for_old_gid (out_layers[i].glyphId, &new_gid)))
return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers);
out_layers[i].glyphId = new_gid;
out_layers[i].colorIdx = c->plan->colr_palettes->get (layers[i].colorIdx);
}
return hb_pair_t<bool, hb_vector_t<LayerRecord>> (true, out_layers);
@ -1044,11 +1075,29 @@ struct COLR
| hb_map_retains_sorting (hb_second)
;
if (unlikely (!base_it || !layer_it || base_it.len () != layer_it.len ()))
if (version == 0 && (!base_it || !layer_it))
return_trace (false);
COLR *colr_prime = c->serializer->start_embed<COLR> ();
return_trace (colr_prime->serialize (c->serializer, version, base_it, layer_it));
bool ret = colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it);
if (version == 0) return_trace (ret);
auto snap = c->serializer->snapshot ();
if (!c->serializer->allocate_size<void> (3 * HBUINT32::static_size)) return_trace (false);
if (!colr_prime->baseGlyphsV1List.serialize_subset (c, baseGlyphsV1List, this))
{
if (c->serializer->in_error ()) return_trace (false);
//no more COLRv1 glyphs: downgrade to version 0
c->serializer->revert (snap);
colr_prime->version = 0;
return_trace (true);
}
if (!colr_prime->layersV1.serialize_subset (c, layersV1, this)) return_trace (false);
colr_prime->varStore = 0;
//TODO: subset varStore once it's implemented in fonttools
return_trace (true);
}
protected:

View File

@ -39,7 +39,6 @@
*/
#define HB_OT_TAG_CPAL HB_TAG('C','P','A','L')
namespace OT {
@ -74,6 +73,58 @@ struct CPALV1Tail
}
public:
bool serialize (hb_serialize_context_t *c,
unsigned palette_count,
unsigned color_count,
const void *base,
const hb_map_t *color_index_map) const
{
TRACE_SERIALIZE (this);
auto *out = c->allocate_size<CPALV1Tail> (static_size);
if (unlikely (!out)) return_trace (false);
const hb_array_t<const HBUINT32> paletteFlags = (base+paletteFlagsZ).as_array (palette_count);
const hb_array_t<const NameID> paletteLabels = (base+paletteLabelsZ).as_array (palette_count);
const hb_array_t<const NameID> colorLabels = (base+colorLabelsZ).as_array (color_count);
c->push ();
for (const auto _ : paletteFlags)
{
if (!c->copy<HBUINT32> (_))
{
c->pop_discard ();
return_trace (false);
}
}
c->add_link (out->paletteFlagsZ, c->pop_pack ());
c->push ();
for (const auto _ : paletteLabels)
{
if (!c->copy<NameID> (_))
{
c->pop_discard ();
return_trace (false);
}
}
c->add_link (out->paletteLabelsZ, c->pop_pack ());
c->push ();
for (const auto _ : colorLabels)
{
if (!color_index_map->has (_)) continue;
NameID new_color_idx;
new_color_idx = color_index_map->get (_);
if (!c->copy<NameID> (new_color_idx))
{
c->pop_discard ();
return_trace (false);
}
}
c->add_link (out->colorLabelsZ, c->pop_pack ());
return_trace (true);
}
bool sanitize (hb_sanitize_context_t *c,
const void *base,
unsigned int palette_count,
@ -157,6 +208,84 @@ struct CPAL
}
public:
bool serialize (hb_serialize_context_t *c,
const hb_array_t<const BGRAColor> &color_records,
const hb_array_t<const HBUINT16> &color_record_indices,
const hb_map_t &color_record_index_map,
const hb_set_t &retained_color_record_indices) const
{
TRACE_SERIALIZE (this);
for (const auto idx : color_record_indices)
{
HBUINT16 new_idx;
if (idx == 0) new_idx = 0;
else new_idx = color_record_index_map.get (idx);
if (!c->copy<HBUINT16> (new_idx)) return_trace (false);
}
c->push ();
for (const auto _ : retained_color_record_indices.iter ())
{
if (!c->copy<BGRAColor> (color_records[_]))
{
c->pop_discard ();
return_trace (false);
}
}
c->add_link (colorRecordsZ, c->pop_pack ());
return_trace (true);
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
const hb_map_t *color_index_map = c->plan->colr_palettes;
if (color_index_map->is_empty ()) return_trace (false);
hb_set_t retained_color_indices;
for (const auto _ : color_index_map->keys ())
{
if (_ == 0xFFFF) continue;
retained_color_indices.add (_);
}
if (retained_color_indices.is_empty ()) return_trace (false);
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->version = version;
out->numColors = retained_color_indices.get_population ();
out->numPalettes = numPalettes;
const hb_array_t<const HBUINT16> colorRecordIndices = colorRecordIndicesZ.as_array (numPalettes);
hb_map_t color_record_index_map;
hb_set_t retained_color_record_indices;
unsigned record_count = 0;
for (const auto first_color_record_idx : colorRecordIndices)
{
for (unsigned retained_color_idx : retained_color_indices.iter ())
{
unsigned color_record_idx = first_color_record_idx + retained_color_idx;
if (color_record_index_map.has (color_record_idx)) continue;
color_record_index_map.set (color_record_idx, record_count);
retained_color_record_indices.add (color_record_idx);
record_count++;
}
}
out->numColorRecords = record_count;
const hb_array_t<const BGRAColor> color_records = (this+colorRecordsZ).as_array (numColorRecords);
if (!out->serialize (c->serializer, color_records, colorRecordIndices, color_record_index_map, retained_color_record_indices))
return_trace (false);
if (version == 1)
return_trace (v1 ().serialize (c->serializer, numPalettes, numColors, this, color_index_map));
return_trace (true);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);

View File

@ -56,6 +56,23 @@ _add_cff_seac_components (const OT::cff1::accelerator_t &cff,
}
#endif
static void
_remap_palette_indexes (const hb_set_t *palette_indexes,
hb_map_t *mapping /* OUT */)
{
unsigned new_idx = 0;
for (unsigned palette_index : palette_indexes->iter ())
{
if (palette_index == 0xFFFF)
{
mapping->set (palette_index, palette_index);
continue;
}
mapping->set (palette_index, new_idx);
new_idx++;
}
}
static void
_remap_indexes (const hb_set_t *indexes,
hb_map_t *mapping /* OUT */)
@ -278,11 +295,14 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
}
_remove_invalid_gids (plan->_glyphset, plan->source->get_num_glyphs ());
hb_set_t palette_indices;
colr.closure_V0palette_indices (plan->_glyphset, &palette_indices);
hb_set_t layer_indices, palette_indices;
hb_set_t layer_indices;
colr.closure_forV1 (plan->_glyphset, &layer_indices, &palette_indices);
_remap_indexes (&layer_indices, plan->colrv1_layers);
_remap_indexes (&palette_indices, plan->colrv1_palettes);
_remap_palette_indexes (&palette_indices, plan->colr_palettes);
colr.fini ();
_remove_invalid_gids (plan->_glyphset, plan->source->get_num_glyphs ());
@ -397,7 +417,7 @@ hb_subset_plan_create (hb_face_t *face,
plan->gsub_features = hb_map_create ();
plan->gpos_features = hb_map_create ();
plan->colrv1_layers = hb_map_create ();
plan->colrv1_palettes = hb_map_create ();
plan->colr_palettes = hb_map_create ();
plan->layout_variation_indices = hb_set_create ();
plan->layout_variation_idx_map = hb_map_create ();
@ -449,7 +469,7 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan)
hb_map_destroy (plan->gsub_features);
hb_map_destroy (plan->gpos_features);
hb_map_destroy (plan->colrv1_layers);
hb_map_destroy (plan->colrv1_palettes);
hb_map_destroy (plan->colr_palettes);
hb_set_destroy (plan->layout_variation_indices);
hb_map_destroy (plan->layout_variation_idx_map);

View File

@ -89,7 +89,7 @@ struct hb_subset_plan_t
//active layers/palettes we'd like to retain
hb_map_t *colrv1_layers;
hb_map_t *colrv1_palettes;
hb_map_t *colr_palettes;
//The set of layout item variation store delta set indices to be retained
hb_set_t *layout_variation_indices;

View File

@ -39,6 +39,7 @@
#include "hb-ot-maxp-table.hh"
#include "hb-ot-color-sbix-table.hh"
#include "hb-ot-color-colr-table.hh"
#include "hb-ot-color-cpal-table.hh"
#include "hb-ot-os2-table.hh"
#include "hb-ot-post-table.hh"
#include "hb-ot-cff1-table.hh"
@ -266,6 +267,7 @@ _subset_table (hb_subset_plan_t *plan, hb_tag_t tag)
case HB_OT_TAG_OS2 : return _subset<const OT::OS2 > (plan);
case HB_OT_TAG_post: return _subset<const OT::post> (plan);
case HB_OT_TAG_COLR: return _subset<const OT::COLR> (plan);
case HB_OT_TAG_CPAL: return _subset<const OT::CPAL> (plan);
case HB_OT_TAG_CBLC: return _subset<const OT::CBLC> (plan);
case HB_OT_TAG_CBDT: return true; /* skip CBDT, handled by CBLC */

Binary file not shown.

View File

@ -0,0 +1,21 @@
FONTS:
TestCOLRv1.ttf
PROFILES:
default.txt
drop-hints.txt
drop-hints-retain-gids.txt
retain-gids.txt
SUBSETS:
#U+E000
#U+E001
#U+E003
U+E004
#U+E000,U+E001
#U+E002,U+E003
U+E000,U+E004
U+E003,U+E004
#U+E000,U+E001,U+E002
#U+E000,U+E001,U+E002,U+E003
*

View File

@ -11,8 +11,12 @@ class Test:
self.subset = subset
def unicodes(self):
import re
if self.subset == '*':
return self.subset[0]
elif re.match("^U\+", self.subset):
s = re.sub (r"U\+", "", self.subset)
return s
else:
return ",".join("%X" % ord(c) for (i, c) in enumerate(self.subset))