[subset] subset both CPAL and COLRv1
This commit is contained in:
parent
466e1fdf5d
commit
f739e1dc6a
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
test/subset/data/expected/colrv1/TestCOLRv1.default.E004.ttf
Normal file
BIN
test/subset/data/expected/colrv1/TestCOLRv1.default.E004.ttf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E004.ttf
Normal file
BIN
test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E004.ttf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E004.ttf
Normal file
BIN
test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E004.ttf
Normal file
Binary file not shown.
Binary file not shown.
BIN
test/subset/data/fonts/TestCOLRv1.ttf
Normal file
BIN
test/subset/data/fonts/TestCOLRv1.ttf
Normal file
Binary file not shown.
21
test/subset/data/tests/colrv1.tests
Normal file
21
test/subset/data/tests/colrv1.tests
Normal 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
|
||||
*
|
@ -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))
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user