Add face-builder

New API:
+hb_face_builder_create
+hb_face_builder_add_table
This commit is contained in:
Behdad Esfahbod 2018-08-25 08:18:53 -07:00
parent 6cac9dc9cc
commit aadb2a9188
7 changed files with 169 additions and 139 deletions

View File

@ -170,6 +170,7 @@ hb_coretext_font_get_ct_font
<SECTION>
<FILE>hb-face</FILE>
hb_face_count
hb_face_t
hb_face_create
hb_face_create_for_tables
hb_face_destroy
@ -188,7 +189,8 @@ hb_face_set_glyph_count
hb_face_set_index
hb_face_set_upem
hb_face_set_user_data
hb_face_t
hb_face_builder_create
hb_face_builder_add_table
</SECTION>
<SECTION>
@ -226,6 +228,7 @@ hb_font_get_glyph
hb_font_get_glyph_advance_for_direction
hb_font_get_glyph_advance_func_t
hb_font_get_glyph_advances_for_direction
hb_font_get_glyph_advances_func_t
hb_font_get_glyph_contour_point
hb_font_get_glyph_contour_point_for_origin
hb_font_get_glyph_contour_point_func_t

View File

@ -512,3 +512,152 @@ hb_face_get_table_tags (const hb_face_t *face,
return ot_face.get_table_tags (start_offset, table_count, table_tags);
}
/*
* face-builder: A face that has add_table().
*/
struct hb_face_builder_data_t
{
struct table_entry_t
{
inline int cmp (const hb_tag_t *t) const
{
if (*t < tag) return -1;
if (*t > tag) return -1;
return 0;
}
hb_tag_t tag;
hb_blob_t *blob;
};
hb_vector_t<table_entry_t, 32> tables;
};
static hb_face_builder_data_t *
_hb_face_builder_data_create (void)
{
hb_face_builder_data_t *data = (hb_face_builder_data_t *) calloc (1, sizeof (hb_face_builder_data_t));
if (unlikely (!data))
return nullptr;
data->tables.init ();
return data;
}
static void
_hb_face_builder_data_destroy (void *user_data)
{
hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
for (unsigned int i = 0; i < data->tables.len; i++)
hb_blob_destroy (data->tables[i].blob);
data->tables.fini ();
free (data);
}
static hb_blob_t *
_hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
{
unsigned int table_count = data->tables.len;
unsigned int face_length = table_count * 16 + 12;
for (unsigned int i = 0; i < table_count; i++)
face_length += hb_ceil_to_4 (hb_blob_get_length (data->tables.arrayZ[i].blob));
char *buf = (char *) malloc (face_length);
if (unlikely (!buf))
return nullptr;
hb_serialize_context_t c (buf, face_length);
OT::OpenTypeFontFile *f = c.start_serialize<OT::OpenTypeFontFile> ();
bool is_cff = data->tables.lsearch (HB_TAG ('C','F','F',' ')) || data->tables.lsearch (HB_TAG ('C','F','F','2'));
hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag;
Supplier<hb_tag_t> tags_supplier (&data->tables[0].tag, table_count, sizeof (data->tables[0]));
Supplier<hb_blob_t *> blobs_supplier (&data->tables[0].blob, table_count, sizeof (data->tables[0]));
bool ret = f->serialize_single (&c,
sfnt_tag,
tags_supplier,
blobs_supplier,
table_count);
c.end_serialize ();
if (unlikely (!ret))
{
free (buf);
return nullptr;
}
return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, free);
}
static hb_blob_t *
_hb_face_builder_reference_table (hb_face_t *face, hb_tag_t tag, void *user_data)
{
hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
if (!tag)
return _hb_face_builder_data_reference_blob (data);
hb_face_builder_data_t::table_entry_t *entry = data->tables.lsearch (tag);
if (entry)
return hb_blob_reference (entry->blob);
return nullptr;
}
/**
* hb_face_builder_create:
*
* Creates a #hb_face_t that can be used with hb_face_builder_add_table().
* After tables are added to the face, it can be compiled to a binary
* font file by calling hb_face_reference_blob().
*
* Return value: (transfer full) New face.
*
* Since: REPLACEME
**/
hb_face_t *
hb_face_builder_create (void)
{
hb_face_builder_data_t *data = _hb_face_builder_data_create ();
if (unlikely (!data)) return hb_face_get_empty ();
return hb_face_create_for_tables (_hb_face_builder_reference_table,
data,
_hb_face_builder_data_destroy);
}
/**
* hb_face_builder_add_table:
*
* Add table for @tag with data provided by @blob to the face. @face must
* be created using hb_face_builder_create().
*
* Since: REPLACEME
**/
hb_bool_t
hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
{
if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy))
return false;
hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
hb_face_builder_data_t::table_entry_t *entry = data->tables.push ();
entry->tag = tag;
entry->blob = hb_blob_reference (blob);
return true;
}

View File

@ -120,6 +120,20 @@ hb_face_get_table_tags (const hb_face_t *face,
unsigned int *table_count, /* IN/OUT */
hb_tag_t *table_tags /* OUT */);
/*
* Builder face.
*/
HB_EXTERN hb_face_t *
hb_face_builder_create (void);
HB_EXTERN hb_bool_t
hb_face_builder_add_table (hb_face_t *face,
hb_tag_t tag,
hb_blob_t *blob);
HB_END_DECLS
#endif /* HB_FACE_H */

View File

@ -154,7 +154,7 @@ hb_subset_plan_create (hb_face_t *face,
plan->unicodes = hb_set_create();
plan->glyphs.init();
plan->source = hb_face_reference (face);
plan->dest = hb_subset_face_create ();
plan->dest = hb_face_builder_create ();
plan->codepoint_to_glyph = hb_map_create();
plan->glyph_map = hb_map_create();

View File

@ -89,7 +89,7 @@ struct hb_subset_plan_t
hb_blob_get_length (contents),
hb_blob_get_length (source_blob));
hb_blob_destroy (source_blob);
return hb_subset_face_add_table(dest, tag, contents);
return hb_face_builder_add_table (dest, tag, contents);
}
};

View File

@ -34,8 +34,6 @@
#include "hb-font-private.hh"
typedef struct hb_subset_face_data_t hb_subset_face_data_t;
struct hb_subset_input_t {
hb_object_header_t header;
ASSERT_POD ();
@ -54,10 +52,5 @@ struct hb_subset_input_t {
*/
};
HB_INTERNAL hb_face_t *
hb_subset_face_create (void);
HB_INTERNAL hb_bool_t
hb_subset_face_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob);
#endif /* HB_SUBSET_PRIVATE_HH */

View File

@ -96,135 +96,6 @@ _subset (hb_subset_plan_t *plan)
}
/*
* A face that has add_table().
*/
struct hb_subset_face_data_t
{
struct table_entry_t
{
inline int cmp (const hb_tag_t *t) const
{
if (*t < tag) return -1;
if (*t > tag) return -1;
return 0;
}
hb_tag_t tag;
hb_blob_t *blob;
};
hb_vector_t<table_entry_t, 32> tables;
};
static hb_subset_face_data_t *
_hb_subset_face_data_create (void)
{
hb_subset_face_data_t *data = (hb_subset_face_data_t *) calloc (1, sizeof (hb_subset_face_data_t));
if (unlikely (!data))
return nullptr;
data->tables.init ();
return data;
}
static void
_hb_subset_face_data_destroy (void *user_data)
{
hb_subset_face_data_t *data = (hb_subset_face_data_t *) user_data;
for (unsigned int i = 0; i < data->tables.len; i++)
hb_blob_destroy (data->tables[i].blob);
data->tables.fini ();
free (data);
}
static hb_blob_t *
_hb_subset_face_data_reference_blob (hb_subset_face_data_t *data)
{
unsigned int table_count = data->tables.len;
unsigned int face_length = table_count * 16 + 12;
for (unsigned int i = 0; i < table_count; i++)
face_length += hb_ceil_to_4 (hb_blob_get_length (data->tables.arrayZ[i].blob));
char *buf = (char *) malloc (face_length);
if (unlikely (!buf))
return nullptr;
hb_serialize_context_t c (buf, face_length);
OT::OpenTypeFontFile *f = c.start_serialize<OT::OpenTypeFontFile> ();
bool is_cff = data->tables.lsearch (HB_TAG ('C','F','F',' ')) || data->tables.lsearch (HB_TAG ('C','F','F','2'));
hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag;
Supplier<hb_tag_t> tags_supplier (&data->tables[0].tag, table_count, sizeof (data->tables[0]));
Supplier<hb_blob_t *> blobs_supplier (&data->tables[0].blob, table_count, sizeof (data->tables[0]));
bool ret = f->serialize_single (&c,
sfnt_tag,
tags_supplier,
blobs_supplier,
table_count);
c.end_serialize ();
if (unlikely (!ret))
{
free (buf);
return nullptr;
}
return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, free);
}
static hb_blob_t *
_hb_subset_face_reference_table (hb_face_t *face, hb_tag_t tag, void *user_data)
{
hb_subset_face_data_t *data = (hb_subset_face_data_t *) user_data;
if (!tag)
return _hb_subset_face_data_reference_blob (data);
hb_subset_face_data_t::table_entry_t *entry = data->tables.lsearch (tag);
if (entry)
return hb_blob_reference (entry->blob);
return nullptr;
}
/* TODO: Move this to hb-face.h and rename to hb_face_builder_create()
* with hb_face_builder_add_table(). */
hb_face_t *
hb_subset_face_create (void)
{
hb_subset_face_data_t *data = _hb_subset_face_data_create ();
if (unlikely (!data)) return hb_face_get_empty ();
return hb_face_create_for_tables (_hb_subset_face_reference_table,
data,
_hb_subset_face_data_destroy);
}
hb_bool_t
hb_subset_face_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
{
if (unlikely (face->destroy != (hb_destroy_func_t) _hb_subset_face_data_destroy))
return false;
hb_subset_face_data_t *data = (hb_subset_face_data_t *) face->user_data;
hb_subset_face_data_t::table_entry_t *entry = data->tables.push ();
entry->tag = tag;
entry->blob = hb_blob_reference (blob);
return true;
}
static bool
_subset_table (hb_subset_plan_t *plan,
hb_tag_t tag)