diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh index a82e2d95d..fe4d78c41 100644 --- a/src/hb-ot-layout-common.hh +++ b/src/hb-ot-layout-common.hh @@ -1757,7 +1757,8 @@ struct VarData shortCount.set (src->shortCount); unsigned int row_size = src->get_row_size (); - if (unlikely (!c->allocate_size (src->regionIndices.get_size () + (row_size * remap.get_count ())))) + unsigned int size = src->regionIndices.get_size () - HBUINT16::static_size/*regionIndices.len*/ + (row_size * remap.get_count ()); + if (unlikely (!c->allocate_size (size))) return_trace (false); memcpy (®ionIndices, &src->regionIndices, src->regionIndices.get_size ()); diff --git a/src/hb-ot-var-gvar-table.hh b/src/hb-ot-var-gvar-table.hh index 77454dcd9..50797bdcd 100644 --- a/src/hb-ot-var-gvar-table.hh +++ b/src/hb-ot-var-gvar-table.hh @@ -422,6 +422,18 @@ struct gvar HBUINT8 *subset_offsets = c->serializer->allocate_size ((long_offset? 4: 2) * (num_glyphs+1)); if (!subset_offsets) return_trace (false); + /* shared tuples */ + if (!sharedTupleCount || !sharedTuples) + out->sharedTuples.set (0); + else + { + unsigned int shared_tuple_size = F2DOT14::static_size * axisCount * sharedTupleCount; + F2DOT14 *tuples = c->serializer->allocate_size (shared_tuple_size); + if (!tuples) return_trace (false); + out->sharedTuples.set ((char *)tuples - (char *)out); + memcpy (tuples, &(this+sharedTuples), shared_tuple_size); + } + char *subset_data = c->serializer->allocate_size(subset_data_size); if (!subset_data) return_trace (false); out->dataZ.set (subset_data - (char *)out); @@ -446,18 +458,6 @@ struct gvar else ((HBUINT16 *)subset_offsets)[num_glyphs].set (glyph_offset / 2); - /* shared tuples */ - if (!sharedTupleCount || !sharedTuples) - out->sharedTuples.set (0); - else - { - unsigned int shared_tuple_size = F2DOT14::static_size * axisCount * sharedTupleCount; - F2DOT14 *tuples = c->serializer->allocate_size (shared_tuple_size); - if (!tuples) return_trace (false); - out->sharedTuples.set ((char *)tuples - (char *)out); - memcpy (tuples, &(this+sharedTuples), shared_tuple_size); - } - return_trace (true); } diff --git a/src/hb-ot-var-hvar-table.hh b/src/hb-ot-var-hvar-table.hh index 21d6b765b..e349e7a52 100644 --- a/src/hb-ot-var-hvar-table.hh +++ b/src/hb-ot-var-hvar-table.hh @@ -134,7 +134,14 @@ struct index_map_subset_plan_t /* Identity map */ if (&index_map == &Null(DeltaSetIndexMap)) + { + outer_remap.add (0); + hb_codepoint_t old_gid; + for (hb_codepoint_t gid = 0; gid < plan->num_output_glyphs (); gid++) + if (plan->old_gid_for_new_gid (gid, &old_gid)) + inner_remaps[0].add (old_gid); return; + } unsigned int last_val = (unsigned int)-1; hb_codepoint_t last_gid = (hb_codepoint_t)-1; @@ -189,6 +196,11 @@ struct index_map_subset_plan_t const hb_bimap_t &outer_remap, const hb_vector_t &inner_remaps) { + /* Leave output_map empty for an identity map */ + /* TODO: if retain_gids, convert identity to a customized map, or not subset varstore? */ + if (input_map == &Null(DeltaSetIndexMap)) + return; + for (unsigned int i = 0; i < max_inners.length; i++) { if (inner_remaps[i].get_count () == 0) continue; @@ -214,6 +226,7 @@ struct index_map_subset_plan_t unsigned int get_size () const { return (map_count? (DeltaSetIndexMap::min_size + get_width () * map_count): 0); } + bool is_identity () const { return get_output_map ().length == 0; } hb_array_t get_output_map () const { return output_map.as_array (); } protected: @@ -311,15 +324,15 @@ struct HVARVVAR const hb_array_t &im_plans) { TRACE_SUBSET (this); - if (!im_plans[ADV_INDEX].get_map_count ()) + if (im_plans[ADV_INDEX].is_identity ()) advMap.set (0); else if (unlikely (!advMap.serialize (c, this).serialize (c, im_plans[ADV_INDEX]))) return_trace (false); - if (!im_plans[LSB_INDEX].get_map_count ()) + if (im_plans[LSB_INDEX].is_identity ()) lsbMap.set (0); else if (unlikely (!lsbMap.serialize (c, this).serialize (c, im_plans[LSB_INDEX]))) return_trace (false); - if (!im_plans[RSB_INDEX].get_map_count ()) + if (im_plans[RSB_INDEX].is_identity ()) rsbMap.set (0); else if (unlikely (!rsbMap.serialize (c, this).serialize (c, im_plans[RSB_INDEX]))) return_trace (false); diff --git a/test/api/Makefile.am b/test/api/Makefile.am index 0f3dab73a..846b00ac4 100644 --- a/test/api/Makefile.am +++ b/test/api/Makefile.am @@ -50,6 +50,8 @@ TEST_PROGS = \ test-subset-vmtx \ test-subset-cff1 \ test-subset-cff2 \ + test-subset-gvar \ + test-subset-hvar \ test-unicode \ test-version \ $(NULL) diff --git a/test/api/fonts/SourceSansVariable-Roman.abc.ttf b/test/api/fonts/SourceSansVariable-Roman.abc.ttf new file mode 100644 index 000000000..690d7d539 Binary files /dev/null and b/test/api/fonts/SourceSansVariable-Roman.abc.ttf differ diff --git a/test/api/fonts/SourceSansVariable-Roman.ac.ttf b/test/api/fonts/SourceSansVariable-Roman.ac.ttf new file mode 100644 index 000000000..2387ea776 Binary files /dev/null and b/test/api/fonts/SourceSansVariable-Roman.ac.ttf differ diff --git a/test/api/test-subset-gvar.c b/test/api/test-subset-gvar.c new file mode 100644 index 000000000..84cd48394 --- /dev/null +++ b/test/api/test-subset-gvar.c @@ -0,0 +1,81 @@ +/* + * Copyright © 2019 Adobe 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. + * + * Adobe Author(s): Michiharu Ariza + */ + +#include "hb-test.h" +#include "hb-subset-test.h" + +/* Unit tests for gvar subsetting */ + +static void +test_subset_gvar_noop (void) +{ + hb_face_t *face_abc = hb_test_open_font_file("fonts/SourceSansVariable-Roman.abc.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_abc_subset; + hb_set_add (codepoints, 'a'); + hb_set_add (codepoints, 'b'); + hb_set_add (codepoints, 'c'); + face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('g','v','a','r')); + + hb_face_destroy (face_abc_subset); + hb_face_destroy (face_abc); +} + +static void +test_subset_gvar (void) +{ + hb_face_t *face_abc = hb_test_open_font_file ("fonts/SourceSansVariable-Roman.abc.ttf"); + hb_face_t *face_ac = hb_test_open_font_file ("fonts/SourceSansVariable-Roman.ac.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_abc_subset; + hb_set_add (codepoints, 'a'); + hb_set_add (codepoints, 'c'); + face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('g','v','a','r')); + + hb_face_destroy (face_abc_subset); + hb_face_destroy (face_abc); + hb_face_destroy (face_ac); +} + + +int +main (int argc, char **argv) +{ + hb_test_init (&argc, &argv); + + hb_test_add (test_subset_gvar_noop); + hb_test_add (test_subset_gvar); + + return hb_test_run (); +} diff --git a/test/api/test-subset-hvar.c b/test/api/test-subset-hvar.c new file mode 100644 index 000000000..0e60cc932 --- /dev/null +++ b/test/api/test-subset-hvar.c @@ -0,0 +1,81 @@ +/* + * Copyright © 2019 Adobe 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. + * + * Adobe Author(s): Michiharu Ariza + */ + +#include "hb-test.h" +#include "hb-subset-test.h" + +/* Unit tests for HVAR subsetting */ + +static void +test_subset_HVAR_noop (void) +{ + hb_face_t *face_abc = hb_test_open_font_file("fonts/SourceSansVariable-Roman.abc.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_abc_subset; + hb_set_add (codepoints, 'a'); + hb_set_add (codepoints, 'b'); + hb_set_add (codepoints, 'c'); + face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('H','V','A','R')); + + hb_face_destroy (face_abc_subset); + hb_face_destroy (face_abc); +} + +static void +test_subset_HVAR (void) +{ + hb_face_t *face_abc = hb_test_open_font_file ("fonts/SourceSansVariable-Roman.abc.ttf"); + hb_face_t *face_ac = hb_test_open_font_file ("fonts/SourceSansVariable-Roman.ac.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_abc_subset; + hb_set_add (codepoints, 'a'); + hb_set_add (codepoints, 'c'); + face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('H','V','A','R')); + + hb_face_destroy (face_abc_subset); + hb_face_destroy (face_abc); + hb_face_destroy (face_ac); +} + + +int +main (int argc, char **argv) +{ + hb_test_init (&argc, &argv); + + hb_test_add (test_subset_HVAR_noop); + hb_test_add (test_subset_HVAR); + + return hb_test_run (); +}