[subset] Fix inefficient ItemVariationStore subsetting w/ retain_gids.

ItemVariationStore is relying on the assumption that the inner_map is populated for all output glyphs, this is not true for subsetting operations with retain gids enabled. Fixes fuzzer timeout: https://oss-fuzz.com/testcase-detail/4575222591520768.
pull/4207/head
Garret Rieger 2 years ago committed by Behdad Esfahbod
parent 491aa572ce
commit 2175f5d050
  1. 9
      src/hb-bimap.hh
  2. 14
      src/hb-ot-layout-common.hh
  3. 10
      src/hb-ot-var-hvar-table.hh
  4. BIN
      test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4575222591520768
  5. BIN
      test/subset/data/expected/variable/Fraunces.retain-gids.26,66,69,124,125.ttf
  6. BIN
      test/subset/data/expected/variable/Fraunces.retain-gids.61.ttf
  7. 1
      test/subset/data/tests/variable.tests

@ -83,9 +83,15 @@ struct hb_bimap_t
unsigned int get_population () const { return forw_map.get_population (); }
protected:
hb_map_t forw_map;
hb_map_t back_map;
public:
auto keys () const HB_AUTO_RETURN (+ forw_map.keys())
auto values () const HB_AUTO_RETURN (+ forw_map.values())
auto iter () const HB_AUTO_RETURN (+ forw_map.iter())
};
/* Inremental bimap: only lhs is given, rhs is incrementally assigned */
@ -108,6 +114,9 @@ struct hb_inc_bimap_t : hb_bimap_t
hb_codepoint_t skip ()
{ return next_value++; }
hb_codepoint_t skip (unsigned count)
{ return next_value += count; }
hb_codepoint_t get_next_value () const
{ return next_value; }

@ -2501,10 +2501,9 @@ struct VarData
{
for (r = 0; r < src_word_count; r++)
{
for (unsigned int i = 0; i < inner_map.get_next_value (); i++)
for (unsigned old_gid : inner_map.keys())
{
unsigned int old = inner_map.backward (i);
int32_t delta = src->get_item_delta_fast (old, r, src_delta_bytes, src_row_size);
int32_t delta = src->get_item_delta_fast (old_gid, r, src_delta_bytes, src_row_size);
if (delta < -65536 || 65535 < delta)
{
has_long = true;
@ -2521,10 +2520,9 @@ struct VarData
bool short_circuit = src_long_words == has_long && src_word_count <= r;
delta_sz[r] = kZero;
for (unsigned int i = 0; i < inner_map.get_next_value (); i++)
for (unsigned old_gid : inner_map.keys())
{
unsigned int old = inner_map.backward (i);
int32_t delta = src->get_item_delta_fast (old, r, src_delta_bytes, src_row_size);
int32_t delta = src->get_item_delta_fast (old_gid, r, src_delta_bytes, src_row_size);
if (delta < min_threshold || max_threshold < delta)
{
delta_sz[r] = kWord;
@ -2585,8 +2583,8 @@ struct VarData
{
unsigned int region = regionIndices.arrayZ[r];
if (region_indices.has (region)) continue;
for (unsigned int i = 0; i < inner_map.get_next_value (); i++)
if (get_item_delta_fast (inner_map.backward (i), r, delta_bytes, row_size) != 0)
for (hb_codepoint_t old_gid : inner_map.keys())
if (get_item_delta_fast (old_gid, r, delta_bytes, row_size) != 0)
{
region_indices.add (region);
break;

@ -185,12 +185,8 @@ struct hvarvvar_subset_plan_t
{
retain_adv_map = plan->flags & HB_SUBSET_FLAGS_RETAIN_GIDS;
outer_map.add (0);
for (hb_codepoint_t gid = 0; gid < plan->num_output_glyphs (); gid++)
{
hb_codepoint_t old_gid;
if (plan->old_gid_for_new_gid (gid, &old_gid))
inner_sets[0]->add (old_gid);
}
for (hb_codepoint_t old_gid : plan->glyphset()->iter())
inner_sets[0]->add (old_gid);
hb_set_union (adv_set, inner_sets[0]);
}
@ -202,10 +198,12 @@ struct hvarvvar_subset_plan_t
if (retain_adv_map)
{
for (hb_codepoint_t gid = 0; gid < plan->num_output_glyphs (); gid++)
{
if (inner_sets[0]->has (gid))
inner_maps[0].add (gid);
else
inner_maps[0].skip ();
}
}
else
{

@ -3,6 +3,7 @@ Fraunces.ttf
PROFILES:
default.txt
retain-gids.txt
SUBSETS:
a

Loading…
Cancel
Save