Created
June 7, 2021 19:45
-
-
Save simoncozens/a36b5df8d2911685d0e64ed447c7cb1b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include "hb.hh" | |
uint64_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = { 0,0,0,0,0}; | |
uint64_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)]; | |
#include "main-font-text.hh" | |
#include "hb-open-type.hh" | |
#define HB_DEBUG 100 | |
#include "hb-subset.hh" | |
#include "hb-open-file.hh" | |
#include "hb-ot-cmap-table.hh" | |
#include "hb-ot-glyf-table.hh" | |
#include "hb-ot-hdmx-table.hh" | |
#include "hb-ot-head-table.hh" | |
#include "hb-ot-hhea-table.hh" | |
#include "hb-ot-hmtx-table.hh" | |
#include "hb-ot-maxp-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-post-table.hh" | |
#include "hb-ot-cff1-table.hh" | |
#include "hb-ot-cff2-table.hh" | |
#include "hb-ot-vorg-table.hh" | |
#include "hb-ot-name-table.hh" | |
#include "hb-ot-color-cbdt-table.hh" | |
#include "hb-ot-layout-gsub-table.hh" | |
#include "hb-ot-layout-gpos-table.hh" | |
#include "hb-ot-var-gvar-table.hh" | |
#include "hb-ot-var-hvar-table.hh" | |
#include "hb-repacker.hh" | |
DEFINE_NULL_NAMESPACE_BYTES (OT, Index) = {0}; | |
DEFINE_NULL_NAMESPACE_BYTES (OT, LangSys) = {0}; | |
DEFINE_NULL_NAMESPACE_BYTES (OT, RangeRecord) = {0}; | |
// static bool | |
// _is_table_present (hb_face_t *source, hb_tag_t tag) | |
// { | |
// hb_tag_t table_tags[32]; | |
// unsigned offset = 0, num_tables = ARRAY_LENGTH (table_tags); | |
// while ((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) | |
// return true; | |
// offset += num_tables; | |
// } | |
// return false; | |
// } | |
static hb_blob_t* | |
always_repack (const hb_serialize_context_t& c) | |
{ | |
hb_vector_t<char> buf; | |
int buf_size = c.end - c.start; | |
if (unlikely (!buf.alloc (buf_size))) { | |
DEBUG_MSG (SUBSET, nullptr, | |
"Couldn't allocate %u bytes.", | |
buf_size); | |
return nullptr; | |
} | |
hb_serialize_context_t repacked ((void *) buf, buf_size); | |
hb_resolve_overflows (c.object_graph (), &repacked); | |
if (unlikely (repacked.in_error ())) { | |
DEBUG_MSG (SUBSET, nullptr, | |
"Repacker errored"); | |
// TODO(garretrieger): refactor so we can share the resize/retry logic with the subset | |
// portion. | |
return nullptr; | |
} | |
DEBUG_MSG (SUBSET, nullptr, | |
"Repacker succeeded"); | |
return repacked.copy_blob (); | |
} | |
template<typename TableType> | |
static | |
bool | |
_try_subset (const TableType *table, | |
hb_vector_t<char>* buf, | |
unsigned buf_size, | |
hb_subset_context_t* c /* OUT */) | |
{ | |
c->serializer->start_serialize<TableType> (); | |
bool needed = table->subset (c); | |
if (!c->serializer->ran_out_of_room ()) | |
{ | |
c->serializer->end_serialize (); | |
return needed; | |
} | |
buf_size += (buf_size >> 1) + 32; | |
DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.", | |
HB_UNTAG (c->table_tag), buf_size); | |
if (unlikely (!buf->alloc (buf_size))) | |
{ | |
DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.", | |
HB_UNTAG (c->table_tag), buf_size); | |
return needed; | |
} | |
c->serializer->reset (buf->arrayZ, buf_size); | |
return _try_subset (table, buf, buf_size, c); | |
} | |
template<typename TableType> | |
static bool | |
repack_and_dump (hb_subset_plan_t* plan) | |
{ | |
hb_blob_t *source_blob = hb_sanitize_context_t ().reference_table<TableType> (plan->source); | |
const TableType *table = source_blob->as<TableType> (); | |
hb_tag_t tag = TableType::tableTag; | |
if (!source_blob->data) | |
{ | |
DEBUG_MSG (SUBSET, nullptr, | |
"OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag)); | |
hb_blob_destroy (source_blob); | |
return false; | |
} | |
hb_vector_t<char> buf; | |
unsigned buf_size = source_blob->length; | |
DEBUG_MSG (SUBSET, nullptr, | |
"OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG (tag), buf_size); | |
if (unlikely (!buf.alloc (buf_size))) | |
{ | |
DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG (tag), buf_size); | |
hb_blob_destroy (source_blob); | |
return false; | |
} | |
hb_serialize_context_t serializer (buf.arrayZ, buf_size); | |
{ | |
hb_subset_context_t c (source_blob, plan, &serializer, tag); | |
_try_subset (table, &buf, buf_size, &c); | |
} | |
DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c before repack", HB_UNTAG (tag)); | |
bool result = false; | |
hb_blob_t *dest_blob = always_repack (serializer); | |
DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c after repack: %p", HB_UNTAG (tag), dest_blob); | |
if (dest_blob) | |
{ | |
DEBUG_MSG (SUBSET, nullptr, | |
"OT::%c%c%c%c final subset table size: %u bytes.", | |
HB_UNTAG (tag), dest_blob->length); | |
result = plan->add_table (tag, dest_blob); | |
} | |
return result; | |
} | |
static bool | |
_add_packed_table (hb_subset_plan_t* plan, hb_tag_t tag) | |
{ | |
DEBUG_MSG (SUBSET, nullptr, "subset %c%c%c%c", HB_UNTAG (tag)); | |
switch (tag) | |
{ | |
case HB_OT_TAG_GDEF: return repack_and_dump<const OT::GDEF> (plan); | |
case HB_OT_TAG_GSUB: return repack_and_dump<const OT::GSUB> (plan); | |
case HB_OT_TAG_GPOS: return repack_and_dump<const OT::GPOS> (plan); | |
default: | |
hb_blob_t *source_table = hb_face_reference_table (plan->source, tag); | |
bool result = hb_face_builder_add_table(plan->dest, tag, source_table); | |
hb_blob_destroy (source_table); | |
return result; | |
} | |
} | |
struct repack_consumer_t | |
{ | |
repack_consumer_t (option_parser_t *parser) | |
: failed (false), options (parser), font (nullptr) {} | |
void init (hb_buffer_t *buffer_, | |
const font_options_t *font_opts) | |
{ | |
font = hb_font_reference (font_opts->get_font ()); | |
} | |
void consume_line (const char *text, | |
unsigned int text_len, | |
const char *text_before, | |
const char *text_after) | |
{ | |
} | |
hb_bool_t | |
write_file (const char *output_file, hb_blob_t *blob) { | |
unsigned int size; | |
const char* data = hb_blob_get_data (blob, &size); | |
if (!output_file) | |
fail (true, "No output file was specified"); | |
FILE *fp = fopen(output_file, "wb"); | |
if (!fp) | |
fail (false, "Cannot open output file `%s': %s", | |
g_filename_display_name (output_file), strerror (errno)); | |
while (size) { | |
size_t ret = fwrite (data, 1, size, fp); | |
size -= ret; | |
data += ret; | |
if (size && ferror (fp)) | |
fail (false, "Failed to write output: %s", strerror (errno)); | |
} | |
fclose (fp); | |
return true; | |
} | |
void finish (const font_options_t *font_opts) | |
{ | |
hb_face_t *face = hb_font_get_face (font); | |
bool success = true; | |
hb_tag_t table_tags[32]; | |
unsigned offset = 0, num_tables = ARRAY_LENGTH (table_tags); | |
// We must use a subset plan in order to use the serializer at all, | |
// so let's make a dummy one that subsets everything... | |
hb_subset_input_t* input = hb_subset_input_create_or_fail(); | |
hb_set_t *codepoints = hb_subset_input_unicode_set (input); | |
hb_set_t *glyphs = hb_subset_input_glyph_set (input); | |
unsigned num_glyphs = hb_face_get_glyph_count (face); | |
if (!input) { | |
printf("Failed to initialize input\n"); | |
return; | |
} | |
hb_face_collect_unicodes (face, codepoints); | |
for (unsigned i = 0; i < num_glyphs; ++i) | |
{ | |
glyphs->add(i); | |
} | |
hb_subset_plan_t *plan = hb_subset_plan_create (face, input); | |
while ((hb_face_get_table_tags (face, offset, &num_tables, table_tags), num_tables)) | |
{ | |
for (unsigned i = 0; i < num_tables; ++i) | |
{ | |
hb_tag_t tag = table_tags[i]; | |
success = _add_packed_table(plan, tag); | |
if (unlikely (!success)) { | |
printf("Failed repacking %c%c%c%c\n", HB_UNTAG(tag)); | |
} | |
} | |
offset += num_tables; | |
} | |
// end: | |
hb_blob_t *result = hb_face_reference_blob (plan->dest); | |
failed = !hb_blob_get_length (result); | |
if (!failed) | |
write_file (options.output_file, result); | |
else | |
printf("Failed\n"); | |
hb_blob_destroy (result); | |
hb_font_destroy (font); | |
} | |
public: | |
bool failed; | |
private: | |
output_options_t options; | |
hb_font_t *font; | |
}; | |
int | |
main (int argc, char **argv) | |
{ | |
main_font_text_t<repack_consumer_t, 10, 0> driver; | |
return driver.main (argc, argv); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment