[subset] Assemble font

This commit is contained in:
Behdad Esfahbod 2018-02-07 21:13:10 -06:00
parent 34ac3548b7
commit c479a59988
7 changed files with 150 additions and 31 deletions

View File

@ -56,6 +56,13 @@ typedef struct TableRecord
int cmp (Tag t) const
{ return t.cmp (tag); }
static int cmp (const void *pa, const void *pb)
{
const TableRecord *a = (const TableRecord *) pa;
const TableRecord *b = (const TableRecord *) pb;
return b->cmp (a->tag);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@ -64,7 +71,7 @@ typedef struct TableRecord
Tag tag; /* 4-byte identifier. */
CheckSum checkSum; /* CheckSum for this table. */
HBUINT32 offset; /* Offset from beginning of TrueType font
Offset32 offset; /* Offset from beginning of TrueType font
* file. */
HBUINT32 length; /* Length of this table. */
public:
@ -118,6 +125,35 @@ typedef struct OffsetTable
}
public:
inline bool serialize (hb_serialize_context_t *c,
hb_tag_t sfnt_tag,
Supplier<hb_tag_t> &tags,
Supplier<hb_blob_t *> &blobs,
unsigned int table_count)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (*this))) return_trace (false);
sfnt_version.set (sfnt_tag);
if (unlikely (!tables.serialize (c, table_count))) return_trace (false);
for (unsigned int i = 0; i < table_count; i++)
{
TableRecord &rec = tables.array[i];
hb_blob_t *blob = blobs[i];
rec.tag.set (tags[0]);
rec.length.set (hb_blob_get_length (blob));
rec.checkSum.set_for_data (hb_blob_get_data (blob, nullptr), rec.length);
rec.offset.serialize (c, this);
void *p = c->allocate_size<void> (rec.length);
if (unlikely (!p)) return false;
memcpy (p, hb_blob_get_data (blob, nullptr), rec.length);
if (rec.length % 4)
p = c->allocate_size<void> (4 - rec.length % 4);
}
tables.qsort ();
return_trace (true);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@ -249,6 +285,18 @@ struct OpenTypeFontFile
}
}
inline bool serialize_single (hb_serialize_context_t *c,
hb_tag_t sfnt_tag,
Supplier<hb_tag_t> &tags,
Supplier<hb_blob_t *> &blobs,
unsigned int table_count)
{
TRACE_SERIALIZE (this);
assert (sfnt_tag != TTCTag);
if (unlikely (!c->extend_min (*this))) return_trace (false);
return_trace (u.fontFace.serialize (c, sfnt_tag, tags, blobs, table_count));
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);

View File

@ -499,15 +499,16 @@ struct hb_serialize_context_t
template <typename Type>
struct Supplier
{
inline Supplier (const Type *array, unsigned int len_)
inline Supplier (const Type *array, unsigned int len_, unsigned int stride_=sizeof(Type))
{
head = array;
len = len_;
stride = stride_;
}
inline const Type operator [] (unsigned int i) const
{
if (unlikely (i >= len)) return Type ();
return head[i];
return * (const Type *) ((const char *) head + stride * i);
}
inline void advance (unsigned int count)
@ -515,7 +516,7 @@ struct Supplier
if (unlikely (count > len))
count = len;
len -= count;
head += count;
head = (const Type *) ((const char *) head + stride * count);
}
private:
@ -523,6 +524,7 @@ struct Supplier
inline Supplier<Type>& operator= (const Supplier<Type> &); /* Disallow copy */
unsigned int len;
unsigned int stride;
const Type *head;
};
@ -717,6 +719,13 @@ struct Offset : Type
inline bool is_null (void) const { return 0 == *this; }
public:
DEFINE_SIZE_STATIC (sizeof(Type));
inline void *serialize (hb_serialize_context_t *c, const void *base)
{
void *t = c->start_embed<void> ();
this->set ((char *) t - (char *) base); /* TODO(serialize) Overflow? */
return t;
}
};
typedef Offset<HBUINT16> Offset16;
@ -786,9 +795,7 @@ struct OffsetTo : Offset<OffsetType>
inline Type& serialize (hb_serialize_context_t *c, const void *base)
{
Type *t = c->start_embed<Type> ();
this->set ((char *) t - (char *) base); /* TODO(serialize) Overflow? */
return *t;
return * (Type *) Offset<OffsetType>::serialize (c, base);
}
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
@ -928,6 +935,11 @@ struct ArrayOf
return -1;
}
inline void qsort (void)
{
::qsort (array, len, sizeof (Type), Type::cmp);
}
private:
inline bool sanitize_shallow (hb_sanitize_context_t *c) const
{
@ -1072,6 +1084,15 @@ struct BinSearchHeader
return_trace (c->check_struct (this));
}
inline void set (unsigned int v)
{
len.set (v);
assert (len == v);
entrySelectorZ.set (MAX (1u, _hb_bit_storage (v)) - 1);
searchRangeZ.set (16 * (1u << entrySelectorZ));
rangeShiftZ.set (16 * MAX (0, (int) v - searchRangeZ));
}
protected:
HBUINT16 len;
HBUINT16 searchRangeZ;

View File

@ -84,28 +84,28 @@ struct hb_ot_map_t
inline hb_mask_t get_global_mask (void) const { return global_mask; }
inline hb_mask_t get_mask (hb_tag_t feature_tag, unsigned int *shift = nullptr) const {
const feature_map_t *map = features.bsearch (&feature_tag);
const feature_map_t *map = features.bsearch (feature_tag);
if (shift) *shift = map ? map->shift : 0;
return map ? map->mask : 0;
}
inline bool needs_fallback (hb_tag_t feature_tag) const {
const feature_map_t *map = features.bsearch (&feature_tag);
const feature_map_t *map = features.bsearch (feature_tag);
return map ? map->needs_fallback : false;
}
inline hb_mask_t get_1_mask (hb_tag_t feature_tag) const {
const feature_map_t *map = features.bsearch (&feature_tag);
const feature_map_t *map = features.bsearch (feature_tag);
return map ? map->_1_mask : 0;
}
inline unsigned int get_feature_index (unsigned int table_index, hb_tag_t feature_tag) const {
const feature_map_t *map = features.bsearch (&feature_tag);
const feature_map_t *map = features.bsearch (feature_tag);
return map ? map->index[table_index] : HB_OT_LAYOUT_NO_FEATURE_INDEX;
}
inline unsigned int get_feature_stage (unsigned int table_index, hb_tag_t feature_tag) const {
const feature_map_t *map = features.bsearch (&feature_tag);
const feature_map_t *map = features.bsearch (feature_tag);
return map ? map->stage[table_index] : (unsigned int) -1;
}

View File

@ -380,6 +380,12 @@ _hb_unsigned_int_mul_overflows (unsigned int count, unsigned int size)
return (size > 0) && (count >= ((unsigned int) -1) / size);
}
static inline unsigned int
_hb_ceil_to_4 (unsigned int v)
{
return ((v - 1) & 3) + 1;
}
/* arrays and maps */
@ -493,34 +499,34 @@ struct hb_prealloced_array_t
}
template <typename T>
inline Type *lsearch (T *x)
inline Type *lsearch (const T &x)
{
for (unsigned int i = 0; i < len; i++)
if (0 == this->array[i].cmp (x))
if (0 == this->array[i].cmp (&x))
return &array[i];
return nullptr;
}
template <typename T>
inline Type *bsearch (T *x)
inline Type *bsearch (const T &x)
{
unsigned int i;
return bfind (x, &i) ? &array[i] : nullptr;
}
template <typename T>
inline const Type *bsearch (T *x) const
inline const Type *bsearch (const T &x) const
{
unsigned int i;
return bfind (x, &i) ? &array[i] : nullptr;
}
template <typename T>
inline bool bfind (T *x, unsigned int *i) const
inline bool bfind (const T &x, unsigned int *i) const
{
int min = 0, max = (int) this->len - 1;
while (min <= max)
{
int mid = (min + max) / 2;
int c = this->array[mid].cmp (x);
int c = this->array[mid].cmp (&x);
if (c < 0)
max = mid - 1;
else if (c > 0)
@ -531,7 +537,7 @@ struct hb_prealloced_array_t
return true;
}
}
if (max < 0 || (max < (int) this->len && this->array[max].cmp (x) > 0))
if (max < 0 || (max < (int) this->len && this->array[max].cmp (&x) > 0))
max++;
*i = max;
return false;

View File

@ -470,7 +470,7 @@ struct hb_set_t
page_map_t map = {get_major (*codepoint), 0};
unsigned int i;
page_map.bfind (&map, &i);
page_map.bfind (map, &i);
if (i < page_map.len)
{
if (pages[page_map[i].index].next (codepoint))
@ -541,7 +541,7 @@ struct hb_set_t
{
page_map_t map = {get_major (g), pages.len};
unsigned int i;
if (!page_map.bfind (&map, &i))
if (!page_map.bfind (map, &i))
{
if (!resize (pages.len + 1))
return nullptr;
@ -555,7 +555,7 @@ struct hb_set_t
inline page_t *page_for (hb_codepoint_t g)
{
page_map_t key = {get_major (g)};
const page_map_t *found = page_map.bsearch (&key);
const page_map_t *found = page_map.bsearch (key);
if (found)
return &pages[found->index];
return nullptr;
@ -563,7 +563,7 @@ struct hb_set_t
inline const page_t *page_for (hb_codepoint_t g) const
{
page_map_t key = {get_major (g)};
const page_map_t *found = page_map.bsearch (&key);
const page_map_t *found = page_map.bsearch (key);
if (found)
return &pages[found->index];
return nullptr;

View File

@ -32,6 +32,7 @@
#include "hb-subset-private.hh"
#include "hb-subset-plan.hh"
#include "hb-open-file-private.hh"
#include "hb-ot-glyf-table.hh"
@ -142,21 +143,59 @@ _hb_subset_face_data_destroy (void *user_data)
{
hb_subset_face_data_t *data = (hb_subset_face_data_t *) user_data;
data->tables.finish ();
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.array[i].blob));
char *buf = (char *) malloc (face_length);
if (unlikely (!buf))
return nullptr;
OT::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;
OT::Supplier<hb_tag_t> tags_supplier (&data->tables[0].tag, table_count, sizeof (data->tables[0]));
OT::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)
{
/* TODO Compile face blob... */
return nullptr;
}
return _hb_subset_face_data_reference_blob (data);
hb_subset_face_data_t::table_entry_t *entry = data->tables.lsearch (&tag);
hb_subset_face_data_t::table_entry_t *entry = data->tables.lsearch (tag);
if (entry)
return hb_blob_reference (entry->blob);
@ -182,7 +221,7 @@ hb_subset_face_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
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.lsearch (&tag);
hb_subset_face_data_t::table_entry_t *entry = data->tables.lsearch (tag);
if (unlikely (!entry))
return false;

View File

@ -32,7 +32,12 @@
/* Unit tests for hb-subset.h */
static const char test_data[] = { 0, 0, 1, 0 };
static const char test_data[] = { 0, 1, 0, 0, /* sfntVersion */
0, 0, /* numTables */
0, 0x10, /* searchRange */
0, 0, /* entrySelector */
0, 0, /* rangeShift */
};
static void
test_subset (void)
@ -51,7 +56,7 @@ test_subset (void)
unsigned int output_length;
const char *output_data = hb_blob_get_data(output, &output_length);
g_assert_cmpmem(test_data, 4, output_data, output_length);
g_assert_cmpmem (test_data, sizeof (test_data), output_data, output_length);
hb_blob_destroy(output);
hb_subset_input_destroy(input);