[subset] Assemble font
This commit is contained in:
parent
34ac3548b7
commit
c479a59988
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user