[subset] Add COLR support
This commit is contained in:
parent
d106900bfd
commit
ed857c4680
|
@ -47,7 +47,7 @@ struct LayerRecord
|
||||||
return_trace (c->check_struct (this));
|
return_trace (c->check_struct (this));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
public:
|
||||||
HBGlyphID glyphId; /* Glyph ID of layer glyph */
|
HBGlyphID glyphId; /* Glyph ID of layer glyph */
|
||||||
Index colorIdx; /* Index value to use with a
|
Index colorIdx; /* Index value to use with a
|
||||||
* selected color palette.
|
* selected color palette.
|
||||||
|
@ -112,6 +112,48 @@ struct COLR
|
||||||
return glyph_layers.length;
|
return glyph_layers.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct accelerator_t
|
||||||
|
{
|
||||||
|
accelerator_t () {}
|
||||||
|
~accelerator_t () { fini(); }
|
||||||
|
|
||||||
|
void init (hb_face_t *face)
|
||||||
|
{
|
||||||
|
colr = hb_sanitize_context_t().reference_table<COLR> (face);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fini ()
|
||||||
|
{
|
||||||
|
this->colr.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_valid ()
|
||||||
|
{
|
||||||
|
return colr.get_blob ()->length;
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_related_glyphs (hb_codepoint_t glyph,
|
||||||
|
hb_set_t *related_ids /* OUT */) const
|
||||||
|
{
|
||||||
|
colr->get_related_glyphs (glyph, related_ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
hb_blob_ptr_t<COLR> colr;
|
||||||
|
};
|
||||||
|
|
||||||
|
void get_related_glyphs (hb_codepoint_t glyph,
|
||||||
|
hb_set_t *related_ids /* OUT */) const
|
||||||
|
{
|
||||||
|
const BaseGlyphRecord &record = (this+baseGlyphsZ).bsearch (numBaseGlyphs, glyph);
|
||||||
|
|
||||||
|
hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers);
|
||||||
|
hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx,
|
||||||
|
record.numLayers);
|
||||||
|
for (unsigned int i = 0; i < glyph_layers.length; i++)
|
||||||
|
hb_set_add (related_ids, glyph_layers[i].glyphId);
|
||||||
|
}
|
||||||
|
|
||||||
bool sanitize (hb_sanitize_context_t *c) const
|
bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
|
@ -120,6 +162,89 @@ struct COLR
|
||||||
(this+layersZ).sanitize (c, numLayers)));
|
(this+layersZ).sanitize (c, numLayers)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Iterator,
|
||||||
|
hb_requires (hb_is_iterator (Iterator))>
|
||||||
|
bool serialize (hb_subset_context_t *c,
|
||||||
|
unsigned version,
|
||||||
|
Iterator it,
|
||||||
|
hb_array_t<const LayerRecord> all_layers)
|
||||||
|
{
|
||||||
|
TRACE_SERIALIZE (this);
|
||||||
|
|
||||||
|
if (unlikely (!c->serializer->extend_min (this))) return_trace (false);
|
||||||
|
this->version = version;
|
||||||
|
numLayers = 0;
|
||||||
|
numBaseGlyphs = it.len ();
|
||||||
|
baseGlyphsZ = COLR::min_size;
|
||||||
|
layersZ = COLR::min_size + numBaseGlyphs * BaseGlyphRecord::min_size;
|
||||||
|
|
||||||
|
if (unlikely (!c->serializer->allocate_size<HBUINT8> ((unsigned int) layersZ - (unsigned int) baseGlyphsZ)))
|
||||||
|
return_trace (false);
|
||||||
|
hb_sorted_array_t<BaseGlyphRecord> glyph_records = (this+baseGlyphsZ).as_array (numBaseGlyphs);
|
||||||
|
|
||||||
|
unsigned int index = 0;
|
||||||
|
for (const hb_item_type<Iterator>& _ : it.iter ())
|
||||||
|
{
|
||||||
|
const unsigned int new_gid = _.first;
|
||||||
|
const BaseGlyphRecord* record = _.second;
|
||||||
|
if (record->firstLayerIdx >= all_layers.length ||
|
||||||
|
record->firstLayerIdx + record->numLayers > all_layers.length)
|
||||||
|
return_trace (false);
|
||||||
|
|
||||||
|
glyph_records[index].glyphId = new_gid;
|
||||||
|
glyph_records[index].numLayers = record->numLayers;
|
||||||
|
glyph_records[index].firstLayerIdx = numLayers;
|
||||||
|
index += 1;
|
||||||
|
|
||||||
|
hb_array_t<const LayerRecord> layers = all_layers.sub_array (record->firstLayerIdx,
|
||||||
|
record->numLayers);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < layers.length; i++)
|
||||||
|
{
|
||||||
|
hb_codepoint_t new_gid = 0;
|
||||||
|
if (unlikely (!c->plan->new_gid_for_old_gid (layers[i].glyphId, &new_gid))) return_trace(false);
|
||||||
|
|
||||||
|
LayerRecord* out_layer = c->serializer->start_embed<LayerRecord> ();
|
||||||
|
if (unlikely (!c->serializer->extend_min (out_layer))) return_trace (false);
|
||||||
|
|
||||||
|
out_layer->glyphId = new_gid;
|
||||||
|
out_layer->colorIdx = layers[i].colorIdx;
|
||||||
|
}
|
||||||
|
numLayers += record->numLayers;
|
||||||
|
}
|
||||||
|
|
||||||
|
return_trace (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool subset (hb_subset_context_t *c) const
|
||||||
|
{
|
||||||
|
TRACE_SUBSET (this);
|
||||||
|
|
||||||
|
auto it =
|
||||||
|
+ hb_range (1u, c->plan->num_output_glyphs ()) // Skip notdef.
|
||||||
|
| hb_map ([&](unsigned int new_gid)
|
||||||
|
{
|
||||||
|
hb_codepoint_t old_gid = 0;
|
||||||
|
if (unlikely (!c->plan->old_gid_for_new_gid (new_gid, &old_gid)))
|
||||||
|
return hb_pair_t<hb_codepoint_t, const BaseGlyphRecord*>(new_gid, nullptr);
|
||||||
|
|
||||||
|
const BaseGlyphRecord* record = &(this+baseGlyphsZ).bsearch (numBaseGlyphs, old_gid);
|
||||||
|
if (record && (hb_codepoint_t) record->glyphId != old_gid)
|
||||||
|
record = nullptr;
|
||||||
|
return hb_pair_t<hb_codepoint_t, const BaseGlyphRecord*>(new_gid, record);
|
||||||
|
})
|
||||||
|
| hb_filter (hb_second)
|
||||||
|
;
|
||||||
|
|
||||||
|
if (unlikely (!it.len ())) return_trace (false);
|
||||||
|
|
||||||
|
COLR *colr_prime = c->serializer->start_embed<COLR> ();
|
||||||
|
|
||||||
|
hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers);
|
||||||
|
|
||||||
|
return_trace (colr_prime->serialize (c, version, it, all_layers));
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
HBUINT16 version; /* Table version number (starts at 0). */
|
HBUINT16 version; /* Table version number (starts at 0). */
|
||||||
HBUINT16 numBaseGlyphs; /* Number of Base Glyph Records. */
|
HBUINT16 numBaseGlyphs; /* Number of Base Glyph Records. */
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "hb-ot-cmap-table.hh"
|
#include "hb-ot-cmap-table.hh"
|
||||||
#include "hb-ot-glyf-table.hh"
|
#include "hb-ot-glyf-table.hh"
|
||||||
#include "hb-ot-cff1-table.hh"
|
#include "hb-ot-cff1-table.hh"
|
||||||
|
#include "hb-ot-color-colr-table.hh"
|
||||||
#include "hb-ot-var-fvar-table.hh"
|
#include "hb-ot-var-fvar-table.hh"
|
||||||
#include "hb-ot-stat-table.hh"
|
#include "hb-ot-stat-table.hh"
|
||||||
|
|
||||||
|
@ -156,11 +157,13 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
|
||||||
#ifndef HB_NO_SUBSET_CFF
|
#ifndef HB_NO_SUBSET_CFF
|
||||||
OT::cff1::accelerator_t cff;
|
OT::cff1::accelerator_t cff;
|
||||||
#endif
|
#endif
|
||||||
|
OT::COLR::accelerator_t colr;
|
||||||
cmap.init (plan->source);
|
cmap.init (plan->source);
|
||||||
glyf.init (plan->source);
|
glyf.init (plan->source);
|
||||||
#ifndef HB_NO_SUBSET_CFF
|
#ifndef HB_NO_SUBSET_CFF
|
||||||
cff.init (plan->source);
|
cff.init (plan->source);
|
||||||
#endif
|
#endif
|
||||||
|
colr.init (plan->source);
|
||||||
|
|
||||||
plan->_glyphset_gsub->add (0); // Not-def
|
plan->_glyphset_gsub->add (0); // Not-def
|
||||||
hb_set_union (plan->_glyphset_gsub, input_glyphs_to_retain);
|
hb_set_union (plan->_glyphset_gsub, input_glyphs_to_retain);
|
||||||
|
@ -201,6 +204,8 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
|
||||||
if (cff.is_valid ())
|
if (cff.is_valid ())
|
||||||
_add_cff_seac_components (cff, gid, plan->_glyphset);
|
_add_cff_seac_components (cff, gid, plan->_glyphset);
|
||||||
#endif
|
#endif
|
||||||
|
if (colr.is_valid ())
|
||||||
|
colr.get_related_glyphs (gid, plan->_glyphset);
|
||||||
}
|
}
|
||||||
|
|
||||||
_remove_invalid_gids (plan->_glyphset, plan->source->get_num_glyphs ());
|
_remove_invalid_gids (plan->_glyphset, plan->source->get_num_glyphs ());
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#include "hb-ot-hmtx-table.hh"
|
#include "hb-ot-hmtx-table.hh"
|
||||||
#include "hb-ot-maxp-table.hh"
|
#include "hb-ot-maxp-table.hh"
|
||||||
#include "hb-ot-color-sbix-table.hh"
|
#include "hb-ot-color-sbix-table.hh"
|
||||||
|
#include "hb-ot-color-colr-table.hh"
|
||||||
#include "hb-ot-os2-table.hh"
|
#include "hb-ot-os2-table.hh"
|
||||||
#include "hb-ot-post-table.hh"
|
#include "hb-ot-post-table.hh"
|
||||||
#include "hb-ot-cff1-table.hh"
|
#include "hb-ot-cff1-table.hh"
|
||||||
|
@ -203,6 +204,9 @@ _subset_table (hb_subset_plan_t *plan,
|
||||||
case HB_OT_TAG_post:
|
case HB_OT_TAG_post:
|
||||||
result = _subset2<const OT::post> (plan);
|
result = _subset2<const OT::post> (plan);
|
||||||
break;
|
break;
|
||||||
|
case HB_OT_TAG_COLR:
|
||||||
|
result = _subset2<const OT::COLR> (plan);
|
||||||
|
break;
|
||||||
|
|
||||||
#ifndef HB_NO_SUBSET_CFF
|
#ifndef HB_NO_SUBSET_CFF
|
||||||
case HB_OT_TAG_cff1:
|
case HB_OT_TAG_cff1:
|
||||||
|
|
|
@ -58,6 +58,7 @@ TEST_PROGS = \
|
||||||
test-subset-vvar \
|
test-subset-vvar \
|
||||||
test-subset-sbix \
|
test-subset-sbix \
|
||||||
test-subset-gpos \
|
test-subset-gpos \
|
||||||
|
test-subset-colr \
|
||||||
test-unicode \
|
test-unicode \
|
||||||
test-version \
|
test-version \
|
||||||
test-subset-nameids \
|
test-subset-nameids \
|
||||||
|
@ -80,6 +81,7 @@ test_subset_vvar_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
|
||||||
test_subset_sbix_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
|
test_subset_sbix_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
|
||||||
test_subset_nameids_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
|
test_subset_nameids_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
|
||||||
test_subset_gpos_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
|
test_subset_gpos_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
|
||||||
|
test_subset_colr_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
|
||||||
|
|
||||||
test_unicode_CPPFLAGS = \
|
test_unicode_CPPFLAGS = \
|
||||||
$(AM_CPPFLAGS) \
|
$(AM_CPPFLAGS) \
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,99 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2020 Google, Inc.
|
||||||
|
*
|
||||||
|
* This is part of HarfBuzz, a text shaping library.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, without written agreement and without
|
||||||
|
* license or royalty fees, to use, copy, modify, and distribute this
|
||||||
|
* software and its documentation for any purpose, provided that the
|
||||||
|
* above copyright notice and the following two paragraphs appear in
|
||||||
|
* all copies of this software.
|
||||||
|
*
|
||||||
|
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||||
|
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||||
|
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
* DAMAGE.
|
||||||
|
*
|
||||||
|
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||||
|
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||||
|
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||||
|
*
|
||||||
|
* Google Author(s): Calder Kitagawa
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hb-test.h"
|
||||||
|
#include "hb-subset-test.h"
|
||||||
|
|
||||||
|
/* Unit tests for COLR subsetting */
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_subset_colr_noop (void)
|
||||||
|
{
|
||||||
|
hb_face_t *face = hb_test_open_font_file ("fonts/TwemojiMozilla.subset.ttf");
|
||||||
|
|
||||||
|
hb_set_t *codepoints = hb_set_create ();
|
||||||
|
hb_face_t *face_subset;
|
||||||
|
hb_set_add (codepoints, '2');
|
||||||
|
hb_set_add (codepoints, 0x3297);
|
||||||
|
hb_set_add (codepoints, 0x3299);
|
||||||
|
face_subset = hb_subset_test_create_subset (face, hb_subset_test_create_input (codepoints));
|
||||||
|
hb_set_destroy (codepoints);
|
||||||
|
|
||||||
|
hb_subset_test_check (face, face_subset, HB_TAG ('C','O','L','R'));
|
||||||
|
|
||||||
|
hb_face_destroy (face_subset);
|
||||||
|
hb_face_destroy (face);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_subset_colr_keep_one_colr_glyph (void)
|
||||||
|
{
|
||||||
|
hb_face_t *face = hb_test_open_font_file ("fonts/TwemojiMozilla.subset.ttf");
|
||||||
|
hb_face_t *face_expected = hb_test_open_font_file ("fonts/TwemojiMozilla.subset.default.3297.ttf");
|
||||||
|
|
||||||
|
hb_set_t *codepoints = hb_set_create ();
|
||||||
|
hb_face_t *face_subset;
|
||||||
|
hb_set_add (codepoints, 0x3297);
|
||||||
|
face_subset = hb_subset_test_create_subset (face, hb_subset_test_create_input (codepoints));
|
||||||
|
hb_set_destroy (codepoints);
|
||||||
|
|
||||||
|
hb_subset_test_check (face_expected, face_subset, HB_TAG ('C','O','L','R'));
|
||||||
|
|
||||||
|
hb_face_destroy (face_subset);
|
||||||
|
hb_face_destroy (face_expected);
|
||||||
|
hb_face_destroy (face);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_subset_colr_keep_no_colr_glyph (void)
|
||||||
|
{
|
||||||
|
hb_face_t *face = hb_test_open_font_file ("fonts/TwemojiMozilla.subset.ttf");
|
||||||
|
hb_face_t *face_expected = hb_test_open_font_file ("fonts/TwemojiMozilla.subset.default.32.ttf");
|
||||||
|
|
||||||
|
hb_set_t *codepoints = hb_set_create ();
|
||||||
|
hb_face_t *face_subset;
|
||||||
|
hb_set_add (codepoints, '2');
|
||||||
|
face_subset = hb_subset_test_create_subset (face, hb_subset_test_create_input (codepoints));
|
||||||
|
hb_set_destroy (codepoints);
|
||||||
|
|
||||||
|
hb_subset_test_check (face_expected, face_subset, HB_TAG ('C','O','L','R'));
|
||||||
|
|
||||||
|
hb_face_destroy (face_subset);
|
||||||
|
hb_face_destroy (face_expected);
|
||||||
|
hb_face_destroy (face);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char **argv)
|
||||||
|
{
|
||||||
|
hb_test_init (&argc, &argv);
|
||||||
|
|
||||||
|
hb_test_add (test_subset_colr_noop);
|
||||||
|
hb_test_add (test_subset_colr_keep_one_colr_glyph);
|
||||||
|
hb_test_add (test_subset_colr_keep_no_colr_glyph);
|
||||||
|
|
||||||
|
return hb_test_run();
|
||||||
|
}
|
Binary file not shown.
|
@ -19,6 +19,7 @@ EXTRA_DIST += \
|
||||||
expected/layout.gsub6 \
|
expected/layout.gsub6 \
|
||||||
expected/cmap14 \
|
expected/cmap14 \
|
||||||
expected/sbix \
|
expected/sbix \
|
||||||
|
expected/colr \
|
||||||
fonts \
|
fonts \
|
||||||
profiles \
|
profiles \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
|
@ -11,6 +11,7 @@ TESTS = \
|
||||||
tests/layout.gsub6.tests \
|
tests/layout.gsub6.tests \
|
||||||
tests/cmap14.tests \
|
tests/cmap14.tests \
|
||||||
tests/sbix.tests \
|
tests/sbix.tests \
|
||||||
|
tests/colr.tests \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
XFAIL_TESTS = \
|
XFAIL_TESTS = \
|
||||||
|
|
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.
|
@ -0,0 +1,17 @@
|
||||||
|
FONTS:
|
||||||
|
TwemojiMozilla.subset.ttf
|
||||||
|
|
||||||
|
PROFILES:
|
||||||
|
default.txt
|
||||||
|
drop-hints.txt
|
||||||
|
drop-hints-retain-gids.txt
|
||||||
|
retain-gids.txt
|
||||||
|
|
||||||
|
SUBSETS:
|
||||||
|
2
|
||||||
|
㊗
|
||||||
|
㊙
|
||||||
|
2㊗
|
||||||
|
2㊙
|
||||||
|
㊗㊙
|
||||||
|
2㊗㊙
|
Loading…
Reference in New Issue