/** * SECTION:hb-subset * @title: hb-subset * @short_description: Subsets font files. * @include: hb-subset.h * * Subsetting reduces the codepoint coverage of font files and removes all data * that is no longer needed. A subset input describes the desired subset. The input is * provided along with a font to the subsetting operation. Output is a new font file * containing only the data specified in the input. * * Currently most outline and bitmap tables are supported: glyf, CFF, CFF2, sbix, * COLR, and CBDT/CBLC. This also includes fonts with variable outlines via OpenType * variations. Notably EBDT/EBLC and SVG are not supported. Layout subsetting is supported * only for OpenType Layout tables (GSUB, GPOS, GDEF). Notably subsetting of graphite or AAT tables * is not yet supported. * * Fonts with graphite or AAT tables may still be subsetted but will likely need to use the * retain glyph ids option and configure the subset to pass through the layout tables untouched.
*/
// If face has 0 tables associated with it, assume that it was built from // hb_face_create_tables and thus is unable to list its tables. Fallback to // checking each table type we can handle for existence instead. auto it =
hb_concat (
+ hb_array (known_tables)
| hb_filter ([&] (hb_tag_t tag) { return !_table_is_empty (plan->source, tag) && !plan->no_subset_tables.has (tag);
})
| hb_map ([] (hb_tag_t tag) -> hb_tag_t { return tag; }),
unsigned bulk = 8192; /* Tables that we want to allocate same space as the source table. For GSUB/GPOS it's
* because those are expensive to subset, so giving them more room is fine. */ bool same_size = table_tag == HB_OT_TAG_GSUB ||
table_tag == HB_OT_TAG_GPOS ||
table_tag == HB_OT_TAG_name;
if (plan->flags & HB_SUBSET_FLAGS_RETAIN_GIDS)
{ if (table_tag == HB_OT_TAG_CFF1)
{ /* Add some extra room for the CFF charset. */
bulk += src_glyphs * 16;
} elseif (table_tag == HB_OT_TAG_CFF2)
{ /* Just extra CharString offsets. */
bulk += src_glyphs * 4;
}
}
if (unlikely (!src_glyphs) || same_size) return bulk + table_len;
if (!hb_face_get_table_tags (source, 0, nullptr, nullptr)) { // If face has 0 tables associated with it, assume that it was built from // hb_face_create_tables and thus is unable to list its tables. Fallback to // checking if the blob associated with tag is empty. return !_table_is_empty (source, tag);
}
hb_tag_t table_tags[32]; unsigned offset = 0, num_tables = ARRAY_LENGTH (table_tags); while (((void) hb_face_get_table_tags (source, offset, &num_tables, table_tags), num_tables))
{ for (unsigned i = 0; i < num_tables; ++i) if (table_tags[i] == tag) returntrue;
offset += num_tables;
} returnfalse;
}
switch (tag)
{ case HB_TAG ('c','v','a','r'): /* hint table, fallthrough */ return plan->all_axes_pinned || (plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
case HB_TAG ('c','v','t',' '): /* hint table, fallthrough */ case HB_TAG ('f','p','g','m'): /* hint table, fallthrough */ case HB_TAG ('p','r','e','p'): /* hint table, fallthrough */ case HB_TAG ('h','d','m','x'): /* hint table, fallthrough */ case HB_TAG ('V','D','M','X'): /* hint table, fallthrough */ return plan->flags & HB_SUBSET_FLAGS_NO_HINTING;
#ifdef HB_NO_SUBSET_LAYOUT // Drop Layout Tables if requested. case HB_OT_TAG_GDEF: case HB_OT_TAG_GPOS: case HB_OT_TAG_GSUB: case HB_TAG ('m','o','r','x'): case HB_TAG ('m','o','r','t'): case HB_TAG ('k','e','r','x'): case HB_TAG ('k','e','r','n'): returntrue; #endif
case HB_TAG ('a','v','a','r'): case HB_TAG ('f','v','a','r'): case HB_TAG ('g','v','a','r'): case HB_OT_TAG_HVAR: case HB_OT_TAG_VVAR: case HB_TAG ('M','V','A','R'): return plan->all_axes_pinned;
default: if (plan->flags & HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED) return _passthrough (plan, tag);
// Drop table returntrue;
}
}
staticvoid _attach_accelerator_data (hb_subset_plan_t* plan,
hb_face_t* face /* IN/OUT */)
{ if (!plan->inprogress_accelerator) return;
// Transfer the accelerator from the plan to us.
hb_subset_accelerator_t* accel = plan->inprogress_accelerator;
plan->inprogress_accelerator = nullptr;
if (accel->in_error ())
{
hb_subset_accelerator_t::destroy (accel); return;
}
// Populate caches that need access to the final tables.
hb_blob_ptr_t<OT::cmap> cmap_ptr (hb_sanitize_context_t ().reference_table<OT::cmap> (face));
accel->cmap_cache = OT::cmap::create_filled_cache (cmap_ptr);
accel->destroy_cmap_cache = OT::SubtableUnicodesCache::destroy;
if (!hb_face_set_user_data(face,
hb_subset_accelerator_t::user_data_key(),
accel,
hb_subset_accelerator_t::destroy, true))
hb_subset_accelerator_t::destroy (accel);
}
/** * hb_subset_or_fail: * @source: font face data to be subset. * @input: input to use for the subsetting. * * Subsets a font according to provided input. Returns nullptr * if the subset operation fails or the face has no glyphs. * * Since: 2.9.0
**/
hb_face_t *
hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input)
{ if (unlikely (!input || !source)) return nullptr;
if (unlikely (!source->get_num_glyphs ()))
{
DEBUG_MSG (SUBSET, nullptr, "No glyphs in source font."); return nullptr;
}
hb_set_t subsetted_tags, pending_subset_tags; while (((void) _get_table_tags (plan, offset, &num_tables, table_tags), num_tables))
{ for (unsigned i = 0; i < num_tables; ++i)
{
hb_tag_t tag = table_tags[i]; if (_should_drop_table (plan, tag)) continue;
pending_subset_tags.add (tag);
}
offset += num_tables;
}
bool success = true;
{ // Grouping to deallocate buf before calling hb_face_reference (plan->dest).
hb_vector_t<char> buf;
buf.alloc (8192 - 16);
while (!pending_subset_tags.is_empty ())
{ if (subsetted_tags.in_error ()
|| pending_subset_tags.in_error ()) {
success = false; goto end;
}
bool made_changes = false; for (hb_tag_t tag : pending_subset_tags)
{ if (!_dependencies_satisfied (plan, tag,
subsetted_tags,
pending_subset_tags))
{ // delayed subsetting for some tables since they might have dependency on other tables // in some cases: e.g: during instantiating glyf tables, hmetrics/vmetrics are updated // and saved in subset plan, hmtx/vmtx subsetting need to use these updated metrics values continue;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.