diff --git a/src/hb-face.cc b/src/hb-face.cc index 5469f327c..973baccf7 100644 --- a/src/hb-face.cc +++ b/src/hb-face.cc @@ -504,7 +504,37 @@ hb_face_reference_table (const hb_face_t *face, hb_blob_t * hb_face_reference_blob (hb_face_t *face) { - return face->reference_table (HB_TAG_NONE); + hb_blob_t *blob = face->reference_table (HB_TAG_NONE); + + if (blob == hb_blob_get_empty ()) + { + // If referencing the face blob is not possible (e.g. not implemented by the + // font functions), use face builder to create a blob out of individual + // table blobs. + unsigned total_count = hb_face_get_table_tags (face, 0, nullptr, nullptr); + if (total_count) + { + hb_tag_t tags[10]; + unsigned count = sizeof (tags) / sizeof (tags[0]); + hb_face_t* builder = hb_face_builder_create (); + + for (unsigned offset = 0; offset < total_count; offset += count) + { + hb_face_get_table_tags (face, offset, &count, tags); + for (unsigned i = 0; i < count; i++) + { + hb_blob_t *table = hb_face_reference_table (face, tags[i]); + hb_face_builder_add_table (builder, tags[i], table); + hb_blob_destroy (table); + } + } + + blob = hb_face_reference_blob (builder); + hb_face_destroy (builder); + } + } + + return blob; } /** diff --git a/test/api/test-font.c b/test/api/test-font.c index c6738b400..9848dae39 100644 --- a/test/api/test-font.c +++ b/test/api/test-font.c @@ -82,11 +82,19 @@ free_up (void *user_data) (*freed)++; } +static hb_tag_t test_tags[] = { + HB_TAG ('a','b','c','d'), + HB_TAG ('e','f','g','h'), +}; + static hb_blob_t * get_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data HB_UNUSED) { - if (tag == HB_TAG ('a','b','c','d')) - return hb_blob_create (test_data, sizeof (test_data), HB_MEMORY_MODE_READONLY, NULL, NULL); + for (unsigned i = 0; i < sizeof (test_tags) / sizeof (test_tags[0]); i++) + { + if (test_tags[i] == tag) + return hb_blob_create (test_data, sizeof (test_data), HB_MEMORY_MODE_READONLY, NULL, NULL); + } return hb_blob_get_empty (); } @@ -119,6 +127,72 @@ test_face_createfortables (void) g_assert (freed); } +static unsigned int +get_table_tags (const hb_face_t *face HB_UNUSED, + unsigned int start_offset, + unsigned int *table_count, + hb_tag_t *table_tags, + void *user_data) +{ + unsigned count = sizeof (test_tags) / sizeof (test_tags[0]); + unsigned end_offset; + + if (!table_count) + return count; + + if (start_offset >= count) + { + *table_count = 0; + return count; + } + + end_offset = start_offset + *table_count; + if (end_offset < start_offset) + { + *table_count = 0; + return count; + } + + end_offset = end_offset < count ? end_offset : count; + + *table_count = end_offset - start_offset; + + for (unsigned i = start_offset; i < end_offset; i++) + table_tags[i - start_offset] = test_tags[i]; + + return count; +} + +static void +test_face_referenceblob (void) +{ + hb_blob_t *blob; + hb_face_t *face; + int freed = 0; + + face = hb_face_create_for_tables (get_table, &freed, free_up); + hb_face_set_get_table_tags_func (face, get_table_tags, NULL, NULL); + + blob = hb_face_reference_blob (face); + hb_face_destroy (face); + + g_assert (blob != hb_blob_get_empty ()); + + face = hb_face_create (blob, 0); + hb_blob_destroy (blob); + + g_assert (face != hb_face_get_empty ()); + g_assert_cmpuint (hb_face_get_table_tags (face, 0, NULL, NULL), ==, sizeof (test_tags) / sizeof (test_tags[0])); + for (unsigned i = 0; i < sizeof (test_tags) / sizeof (test_tags[0]); i++) + { + hb_blob_t* table = hb_face_reference_table (face, test_tags[i]); + g_assert (table != hb_blob_get_empty ()); + hb_blob_destroy (table); + } + + hb_face_destroy (face); +} + static void _test_font_nil_funcs (hb_font_t *font) { @@ -606,6 +680,7 @@ main (int argc, char **argv) hb_test_add (test_face_empty); hb_test_add (test_face_create); hb_test_add (test_face_createfortables); + hb_test_add (test_face_referenceblob); hb_test_add (test_fontfuncs_empty); hb_test_add (test_fontfuncs_nil);