Add retain_gids option to subset input. Update glyf and loca handling to respect retain_gids.

This commit is contained in:
Garret Rieger 2019-01-17 18:55:56 -08:00
parent fe53292310
commit b7f971884e
5 changed files with 74 additions and 13 deletions

View File

@ -32,6 +32,7 @@
static bool static bool
_calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf, _calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf,
hb_vector_t<hb_codepoint_t> &glyph_ids, hb_vector_t<hb_codepoint_t> &glyph_ids,
const hb_map_t *glyph_map,
hb_bool_t drop_hints, hb_bool_t drop_hints,
bool *use_short_loca /* OUT */, bool *use_short_loca /* OUT */,
unsigned int *glyf_size /* OUT */, unsigned int *glyf_size /* OUT */,
@ -39,9 +40,12 @@ _calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf,
hb_vector_t<unsigned int> *instruction_ranges /* OUT */) hb_vector_t<unsigned int> *instruction_ranges /* OUT */)
{ {
unsigned int total = 0; unsigned int total = 0;
hb_codepoint_t max_new_gid = 0;
for (unsigned int i = 0; i < glyph_ids.length; i++) for (unsigned int i = 0; i < glyph_ids.length; i++)
{ {
hb_codepoint_t next_glyph = glyph_ids[i]; hb_codepoint_t next_glyph = glyph_ids[i];
hb_codepoint_t next_glyph_new_gid = glyph_map->get (next_glyph);
max_new_gid = MAX (max_new_gid, next_glyph_new_gid);
if (!instruction_ranges->resize (instruction_ranges->length + 2)) if (!instruction_ranges->resize (instruction_ranges->length + 2))
{ {
DEBUG_MSG(SUBSET, nullptr, "Failed to resize instruction_ranges."); DEBUG_MSG(SUBSET, nullptr, "Failed to resize instruction_ranges.");
@ -79,7 +83,7 @@ _calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf,
*glyf_size = total; *glyf_size = total;
*use_short_loca = (total <= 131070); *use_short_loca = (total <= 131070);
*loca_size = (glyph_ids.length + 1) *loca_size = (max_new_gid + 2)
* (*use_short_loca ? sizeof (OT::HBUINT16) : sizeof (OT::HBUINT32)); * (*use_short_loca ? sizeof (OT::HBUINT16) : sizeof (OT::HBUINT32));
DEBUG_MSG(SUBSET, nullptr, "preparing to subset glyf: final size %d, loca size %d, using %s loca", DEBUG_MSG(SUBSET, nullptr, "preparing to subset glyf: final size %d, loca size %d, using %s loca",
@ -117,7 +121,7 @@ _write_loca_entry (unsigned int id,
} }
static void static void
_update_components (hb_subset_plan_t * plan, _update_components (const hb_subset_plan_t *plan,
char *glyph_start, char *glyph_start,
unsigned int length) unsigned int length)
{ {
@ -153,7 +157,7 @@ static bool _remove_composite_instruction_flag (char *glyf_prime, unsigned int l
} }
static bool static bool
_write_glyf_and_loca_prime (hb_subset_plan_t *plan, _write_glyf_and_loca_prime (const hb_subset_plan_t *plan,
const OT::glyf::accelerator_t &glyf, const OT::glyf::accelerator_t &glyf,
const char *glyf_data, const char *glyf_data,
bool use_short_loca, bool use_short_loca,
@ -163,12 +167,27 @@ _write_glyf_and_loca_prime (hb_subset_plan_t *plan,
unsigned int loca_prime_size, unsigned int loca_prime_size,
char *loca_prime_data /* OUT */) char *loca_prime_data /* OUT */)
{ {
hb_vector_t<hb_codepoint_t> &glyph_ids = plan->glyphs; const hb_vector_t<hb_codepoint_t> &glyph_ids = plan->glyphs;
const hb_map_t *glyph_map = plan->glyph_map;
char *glyf_prime_data_next = glyf_prime_data; char *glyf_prime_data_next = glyf_prime_data;
bool success = true; bool success = true;
hb_codepoint_t gid = 0;
for (unsigned int i = 0; i < glyph_ids.length; i++) for (unsigned int i = 0; i < glyph_ids.length; i++)
{ {
while (gid < glyph_map->get (glyph_ids[i]))
{
// If we are retaining existing gids then there will potentially be gaps
// in the loca table between glyphs. Fill in this gap with glyphs that have
// no outlines.
success = success && _write_loca_entry (gid,
glyf_prime_data_next - glyf_prime_data,
use_short_loca,
loca_prime_data,
loca_prime_size);
gid++;
}
unsigned int start_offset, end_offset; unsigned int start_offset, end_offset;
if (unlikely (!(glyf.get_offsets (glyph_ids[i], &start_offset, &end_offset) && if (unlikely (!(glyf.get_offsets (glyph_ids[i], &start_offset, &end_offset) &&
glyf.remove_padding (start_offset, &end_offset)))) glyf.remove_padding (start_offset, &end_offset))))
@ -204,7 +223,7 @@ _write_glyf_and_loca_prime (hb_subset_plan_t *plan,
memset (glyf_prime_data_next + instruction_start - start_offset - 2, 0, 2); memset (glyf_prime_data_next + instruction_start - start_offset - 2, 0, 2);
} }
success = success && _write_loca_entry (i, success = success && _write_loca_entry (gid,
glyf_prime_data_next - glyf_prime_data, glyf_prime_data_next - glyf_prime_data,
use_short_loca, use_short_loca,
loca_prime_data, loca_prime_data,
@ -213,9 +232,10 @@ _write_glyf_and_loca_prime (hb_subset_plan_t *plan,
// TODO: don't align to two bytes if using long loca. // TODO: don't align to two bytes if using long loca.
glyf_prime_data_next += length + (length % 2); // Align to 2 bytes for short loca. glyf_prime_data_next += length + (length % 2); // Align to 2 bytes for short loca.
gid++;
} }
success = success && _write_loca_entry (glyph_ids.length, success = success && _write_loca_entry (gid,
glyf_prime_data_next - glyf_prime_data, glyf_prime_data_next - glyf_prime_data,
use_short_loca, use_short_loca,
loca_prime_data, loca_prime_data,
@ -241,6 +261,7 @@ _hb_subset_glyf_and_loca (const OT::glyf::accelerator_t &glyf,
if (unlikely (!_calculate_glyf_and_loca_prime_size (glyf, if (unlikely (!_calculate_glyf_and_loca_prime_size (glyf,
glyphs_to_retain, glyphs_to_retain,
plan->glyph_map,
plan->drop_hints, plan->drop_hints,
use_short_loca, use_short_loca,
&glyf_prime_size, &glyf_prime_size,

View File

@ -44,7 +44,10 @@ hb_subset_input_create_or_fail ()
input->unicodes = hb_set_create (); input->unicodes = hb_set_create ();
input->glyphs = hb_set_create (); input->glyphs = hb_set_create ();
input->drop_hints = false;
input->drop_layout = true; input->drop_layout = true;
input->desubroutinize = false;
input->retain_gids = false;
return input; return input;
} }
@ -144,3 +147,27 @@ hb_subset_input_get_desubroutinize (hb_subset_input_t *subset_input)
{ {
return subset_input->desubroutinize; return subset_input->desubroutinize;
} }
/**
* hb_subset_input_set_retain_gids:
* @subset_input: a subset_input.
* @retain_gids: If true the subsetter will not renumber glyph ids.
* Since: REPLACEME
**/
HB_EXTERN void
hb_subset_input_set_retain_gids (hb_subset_input_t *subset_input,
hb_bool_t retain_gids)
{
subset_input->retain_gids = retain_gids;
}
/**
* hb_subset_input_get_retain_gids:
* Returns: value of retain_gids.
* Since: REPLACEME
**/
HB_EXTERN hb_bool_t
hb_subset_input_get_retain_gids (hb_subset_input_t *subset_input)
{
return subset_input->retain_gids;
}

View File

@ -44,6 +44,7 @@ struct hb_subset_input_t
bool drop_hints : 1; bool drop_hints : 1;
bool drop_layout : 1; bool drop_layout : 1;
bool desubroutinize : 1; bool desubroutinize : 1;
bool retain_gids : 1;
/* TODO /* TODO
* *
* features * features

View File

@ -156,11 +156,15 @@ _populate_gids_to_retain (hb_face_t *face,
} }
static void static void
_create_old_gid_to_new_gid_map (const hb_vector_t<hb_codepoint_t> &glyphs, _create_old_gid_to_new_gid_map (bool retain_gids,
const hb_vector_t<hb_codepoint_t> &glyphs,
hb_map_t *glyph_map) hb_map_t *glyph_map)
{ {
for (unsigned int i = 0; i < glyphs.length; i++) { for (unsigned int i = 0; i < glyphs.length; i++) {
if (!retain_gids)
glyph_map->set (glyphs[i], i); glyph_map->set (glyphs[i], i);
else
glyph_map->set (glyphs[i], glyphs[i]);
} }
} }
@ -195,7 +199,9 @@ hb_subset_plan_create (hb_face_t *face,
plan->unicodes, plan->unicodes,
plan->codepoint_to_glyph, plan->codepoint_to_glyph,
&plan->glyphs); &plan->glyphs);
_create_old_gid_to_new_gid_map (plan->glyphs,
_create_old_gid_to_new_gid_map (input->retain_gids,
plan->glyphs,
plan->glyph_map); plan->glyph_map);
return plan; return plan;

View File

@ -72,6 +72,12 @@ hb_subset_input_set_desubroutinize (hb_subset_input_t *subset_input,
HB_EXTERN hb_bool_t HB_EXTERN hb_bool_t
hb_subset_input_get_desubroutinize (hb_subset_input_t *subset_input); hb_subset_input_get_desubroutinize (hb_subset_input_t *subset_input);
HB_EXTERN void
hb_subset_input_set_retain_gids (hb_subset_input_t *subset_input,
hb_bool_t retain_gids);
HB_EXTERN hb_bool_t
hb_subset_input_get_retain_gids (hb_subset_input_t *subset_input);
/* hb_subset () */ /* hb_subset () */
HB_EXTERN hb_face_t * HB_EXTERN hb_face_t *
hb_subset (hb_face_t *source, hb_subset_input_t *input); hb_subset (hb_face_t *source, hb_subset_input_t *input);