Add face-builder
New API: +hb_face_builder_create +hb_face_builder_add_table
This commit is contained in:
parent
6cac9dc9cc
commit
aadb2a9188
@ -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
|
||||
|
149
src/hb-face.cc
149
src/hb-face.cc
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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 */
|
||||
|
129
src/hb-subset.cc
129
src/hb-subset.cc
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user