First pass at building a cmap
This commit is contained in:
parent
d2170d1478
commit
9275bd03ea
|
@ -254,6 +254,8 @@ struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32 > {};
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct CmapSubtableLongSegmented
|
struct CmapSubtableLongSegmented
|
||||||
{
|
{
|
||||||
|
friend struct cmap;
|
||||||
|
|
||||||
inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
|
inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
|
||||||
{
|
{
|
||||||
int i = groups.bsearch (codepoint);
|
int i = groups.bsearch (codepoint);
|
||||||
|
@ -269,6 +271,20 @@ struct CmapSubtableLongSegmented
|
||||||
return_trace (c->check_struct (this) && groups.sanitize (c));
|
return_trace (c->check_struct (this) && groups.sanitize (c));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool serialize(hb_serialize_context_t *context,
|
||||||
|
unsigned int group_count,
|
||||||
|
Supplier<CmapSubtableLongGroup> &group_supplier)
|
||||||
|
{
|
||||||
|
TRACE_SERIALIZE (this);
|
||||||
|
if (unlikely(!context->extend_min (*this))) return_trace (false);
|
||||||
|
if (unlikely(!groups.serialize(context, group_count))) return_trace (false);
|
||||||
|
for (unsigned int i = 0; i < group_count; i++) {
|
||||||
|
const CmapSubtableLongGroup &group = group_supplier[i];
|
||||||
|
memcpy(&groups[i], &group, sizeof(group));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
HBUINT16 format; /* Subtable format; set to 12. */
|
HBUINT16 format; /* Subtable format; set to 12. */
|
||||||
HBUINT16 reservedZ; /* Reserved; set to 0. */
|
HBUINT16 reservedZ; /* Reserved; set to 0. */
|
||||||
|
@ -505,15 +521,15 @@ struct cmap
|
||||||
encodingRecord.sanitize (c, this));
|
encodingRecord.sanitize (c, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool subset (hb_subset_plan_t *plan, hb_face_t *source, hb_face_t *dest) const
|
inline void populate_groups(hb_auto_array_t<hb_codepoint_t> &codepoints,
|
||||||
|
hb_auto_array_t<CmapSubtableLongGroup> *groups) const
|
||||||
{
|
{
|
||||||
hb_auto_array_t<CmapSubtableLongGroup> groups;
|
|
||||||
CmapSubtableLongGroup *group = nullptr;
|
CmapSubtableLongGroup *group = nullptr;
|
||||||
for (unsigned int i = 0; i < plan->codepoints.len; i++) {
|
for (unsigned int i = 0; i < codepoints.len; i++) {
|
||||||
hb_codepoint_t cp = plan->codepoints[i];
|
hb_codepoint_t cp = codepoints[i];
|
||||||
if (!group)
|
if (!group)
|
||||||
{
|
{
|
||||||
group = groups.push();
|
group = groups->push();
|
||||||
group->startCharCode.set(cp);
|
group->startCharCode.set(cp);
|
||||||
group->endCharCode.set(cp);
|
group->endCharCode.set(cp);
|
||||||
group->glyphID.set(i); // index in codepoints is new gid
|
group->glyphID.set(i); // index in codepoints is new gid
|
||||||
|
@ -527,13 +543,84 @@ struct cmap
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_MSG(SUBSET, nullptr, "cmap");
|
DEBUG_MSG(SUBSET, nullptr, "cmap");
|
||||||
for (unsigned int i = 0; i < groups.len; i++) {
|
for (unsigned int i = 0; i < groups->len; i++) {
|
||||||
CmapSubtableLongGroup& group = groups[i];
|
CmapSubtableLongGroup& group = (*groups)[i];
|
||||||
DEBUG_MSG(SUBSET, nullptr, " %d: U+%04X-U+%04X, first gid %d", i, (uint32_t) group.startCharCode, (uint32_t) group.endCharCode, (uint32_t) group.glyphID);
|
DEBUG_MSG(SUBSET, nullptr, " %d: U+%04X-U+%04X, gid %d-%d", i, (uint32_t) group.startCharCode, (uint32_t) group.endCharCode, (uint32_t) group.glyphID, (uint32_t) group.glyphID + ((uint32_t) group.endCharCode - (uint32_t) group.startCharCode));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hb_bool_t _subset (hb_auto_array_t<CmapSubtableLongGroup> &groups,
|
||||||
|
size_t dest_sz,
|
||||||
|
void *dest) const
|
||||||
|
{
|
||||||
|
hb_serialize_context_t context(dest, dest_sz);
|
||||||
|
|
||||||
|
OT::cmap *cmap = context.start_serialize<OT::cmap> ();
|
||||||
|
if (unlikely(!context.extend_min(*cmap)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmap->version.set(0);
|
||||||
|
|
||||||
|
if (unlikely(!cmap->encodingRecord.serialize(&context, /* numTables */ 1)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
EncodingRecord &rec = cmap->encodingRecord[0];
|
||||||
|
rec.platformID.set (3); // Windows
|
||||||
|
rec.encodingID.set (1); // Unicode BMP
|
||||||
|
|
||||||
|
CmapSubtable &subtable = rec.subtable.serialize(&context, &rec.subtable);
|
||||||
|
subtable.u.format.set(12);
|
||||||
|
|
||||||
|
CmapSubtableFormat12 &format12 = subtable.u.format12;
|
||||||
|
format12.format.set(12);
|
||||||
|
format12.reservedZ.set(0);
|
||||||
|
|
||||||
|
OT::Supplier<CmapSubtableLongGroup> group_supplier (&groups[0], groups.len, sizeof (CmapSubtableLongGroup));
|
||||||
|
if (unlikely(!format12.serialize(&context, groups.len, group_supplier)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.end_serialize ();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hb_blob_t * subset (hb_subset_plan_t *plan, hb_face_t *source) const
|
||||||
|
{
|
||||||
|
hb_auto_array_t<CmapSubtableLongGroup> groups;
|
||||||
|
|
||||||
|
populate_groups(plan->codepoints, &groups);
|
||||||
|
|
||||||
|
// We now know how big our blob needs to be
|
||||||
|
// TODO use APIs from the structs to get size?
|
||||||
|
size_t dest_sz = 4 // header
|
||||||
|
+ 8 // 1 EncodingRecord
|
||||||
|
+ 16 // Format 12 header
|
||||||
|
+ 12 * groups.len; // SequentialMapGroup records
|
||||||
|
void *dest = calloc(dest_sz, 1);
|
||||||
|
if (unlikely(!dest)) {
|
||||||
|
DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %ld for cmap subset output", dest_sz);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unlikely(!_subset(groups, dest_sz, dest)))
|
||||||
|
{
|
||||||
|
free(dest);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// all done, write the blob into dest
|
||||||
|
return hb_blob_create((const char *)dest,
|
||||||
|
dest_sz,
|
||||||
|
HB_MEMORY_MODE_READONLY,
|
||||||
|
/* userdata */ nullptr,
|
||||||
|
free);
|
||||||
|
}
|
||||||
|
|
||||||
struct accelerator_t
|
struct accelerator_t
|
||||||
{
|
{
|
||||||
inline void init (hb_face_t *face)
|
inline void init (hb_face_t *face)
|
||||||
|
|
|
@ -108,19 +108,19 @@ hb_subset_input_destroy(hb_subset_input_t *subset_input)
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename TableType>
|
template<typename TableType>
|
||||||
hb_bool_t
|
hb_blob_t *
|
||||||
subset (hb_subset_plan_t *plan, hb_face_t *source, hb_face_t *dest)
|
_subset (hb_subset_plan_t *plan, hb_face_t *source)
|
||||||
{
|
{
|
||||||
OT::Sanitizer<TableType> sanitizer;
|
OT::Sanitizer<TableType> sanitizer;
|
||||||
hb_blob_t *table_blob = sanitizer.sanitize (source->reference_table (TableType::tableTag));
|
hb_blob_t *source_blob = sanitizer.sanitize (source->reference_table (TableType::tableTag));
|
||||||
if (unlikely(!table_blob)) {
|
if (unlikely(!source_blob)) {
|
||||||
DEBUG_MSG(SUBSET, nullptr, "Failed to reference table for tag %d", TableType::tableTag);
|
DEBUG_MSG(SUBSET, nullptr, "Failed to reference table for tag %d", TableType::tableTag);
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
const TableType *table = OT::Sanitizer<TableType>::lock_instance (table_blob);
|
const TableType *table = OT::Sanitizer<TableType>::lock_instance (source_blob);
|
||||||
hb_bool_t result = table->subset(plan, source, dest);
|
hb_blob_t *result = table->subset(plan, source);
|
||||||
|
|
||||||
hb_blob_destroy (table_blob);
|
hb_blob_destroy (source_blob);
|
||||||
|
|
||||||
hb_tag_t tag = TableType::tableTag;
|
hb_tag_t tag = TableType::tableTag;
|
||||||
DEBUG_MSG(SUBSET, nullptr, "Subset %c%c%c%c %s", HB_UNTAG(tag), result ? "success" : "FAILED!");
|
DEBUG_MSG(SUBSET, nullptr, "Subset %c%c%c%c %s", HB_UNTAG(tag), result ? "success" : "FAILED!");
|
||||||
|
@ -242,7 +242,6 @@ hb_subset_face_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
hb_subset_face_data_t *data = (hb_subset_face_data_t *) face->user_data;
|
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 ();
|
hb_subset_face_data_t::table_entry_t *entry = data->tables.push ();
|
||||||
if (unlikely (!entry))
|
if (unlikely (!entry))
|
||||||
return false;
|
return false;
|
||||||
|
@ -306,10 +305,12 @@ bool
|
||||||
_subset_table (hb_subset_plan_t *plan,
|
_subset_table (hb_subset_plan_t *plan,
|
||||||
hb_face_t *source,
|
hb_face_t *source,
|
||||||
hb_tag_t tag,
|
hb_tag_t tag,
|
||||||
hb_blob_t *table_blob,
|
hb_blob_t *source_blob,
|
||||||
hb_face_t *dest)
|
hb_face_t *dest)
|
||||||
{
|
{
|
||||||
// TODO (grieger): Handle updating the head table (loca format + num glyphs)
|
// TODO (grieger): Handle updating the head table (loca format + num glyphs)
|
||||||
|
DEBUG_MSG(SUBSET, nullptr, "begin subset %c%c%c%c", HB_UNTAG(tag));
|
||||||
|
hb_blob_t *dest_blob;
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
case HB_OT_TAG_glyf:
|
case HB_OT_TAG_glyf:
|
||||||
return _subset_glyf (plan, source, dest);
|
return _subset_glyf (plan, source, dest);
|
||||||
|
@ -320,14 +321,16 @@ _subset_table (hb_subset_plan_t *plan,
|
||||||
// SKIP loca, it's handle by glyf
|
// SKIP loca, it's handle by glyf
|
||||||
return true;
|
return true;
|
||||||
case HB_OT_TAG_cmap:
|
case HB_OT_TAG_cmap:
|
||||||
// TODO(rsheeter): remove hb_subset_face_add_table
|
dest_blob = _subset<const OT::cmap> (plan, source);
|
||||||
// once cmap subsetting works.
|
break;
|
||||||
hb_subset_face_add_table (dest, tag, table_blob);
|
|
||||||
return subset<const OT::cmap> (plan, source, dest);
|
|
||||||
default:
|
default:
|
||||||
// Default action, copy table as is.
|
dest_blob = source_blob;
|
||||||
return hb_subset_face_add_table (dest, tag, table_blob);
|
break;
|
||||||
}
|
}
|
||||||
|
DEBUG_MSG(SUBSET, nullptr, "subset %c%c%c%c %s", HB_UNTAG(tag), dest_blob ? "ok" : "FAILED");
|
||||||
|
if (unlikely(!dest_blob)) return false;
|
||||||
|
if (unlikely(!hb_subset_face_add_table (dest, tag, dest_blob))) return false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue