Merge pull request from harfbuzz/face-blob

[face] Add fallback implementation to hb_face_reference_blob
This commit is contained in:
Behdad Esfahbod 2025-02-04 18:43:33 +00:00 committed by GitHub
commit 7d17ea4996
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 119 additions and 8 deletions

View file

@ -493,9 +493,10 @@ hb_face_reference_table (const hb_face_t *face,
* hb_face_reference_blob:
* @face: A face object
*
* Fetches a pointer to the binary blob that contains the
* specified face. Returns an empty blob if referencing face data is not
* possible.
* Fetches a pointer to the binary blob that contains the specified face.
* If referencing the face data is not possible, this function creates a blob
* out of individual table blobs if hb_face_get_table_tags() works with this
* face, otherwise it returns an empty blob.
*
* Return value: (transfer full): A pointer to the blob for @face
*
@ -504,7 +505,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;
}
/**

View file

@ -73,9 +73,14 @@ hb_face_create_from_file_or_fail (const char *file_name,
* @tag: the tag of the table to reference
* @user_data: User data pointer passed by the caller
*
* Callback function for hb_face_create_for_tables().
* Callback function for hb_face_create_for_tables(). The @tag is the tag of the
* table to reference, and the special tag #HB_TAG_NONE is used to reference the
* blob of the face itself. If referencing the face blob is not possible, it is
* recommended to set hb_get_table_tags_func_t on the @face to allow
* hb_face_reference_blob() to create a face blob out of individual table blobs.
*
* Return value: (transfer full): A pointer to the @tag table within @face
* Return value: (transfer full): A pointer to the @tag table within @face or
* `NULL` if the table is not found or cannot be referenced.
*
* Since: 0.9.2
*/

View file

@ -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);