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>
|
||||
struct CmapSubtableLongSegmented
|
||||
{
|
||||
friend struct cmap;
|
||||
|
||||
inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
|
||||
{
|
||||
int i = groups.bsearch (codepoint);
|
||||
@ -269,6 +271,20 @@ struct CmapSubtableLongSegmented
|
||||
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:
|
||||
HBUINT16 format; /* Subtable format; set to 12. */
|
||||
HBUINT16 reservedZ; /* Reserved; set to 0. */
|
||||
@ -505,15 +521,15 @@ struct cmap
|
||||
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;
|
||||
for (unsigned int i = 0; i < plan->codepoints.len; i++) {
|
||||
hb_codepoint_t cp = plan->codepoints[i];
|
||||
for (unsigned int i = 0; i < codepoints.len; i++) {
|
||||
hb_codepoint_t cp = codepoints[i];
|
||||
if (!group)
|
||||
{
|
||||
group = groups.push();
|
||||
group = groups->push();
|
||||
group->startCharCode.set(cp);
|
||||
group->endCharCode.set(cp);
|
||||
group->glyphID.set(i); // index in codepoints is new gid
|
||||
@ -527,13 +543,84 @@ struct cmap
|
||||
}
|
||||
|
||||
DEBUG_MSG(SUBSET, nullptr, "cmap");
|
||||
for (unsigned int i = 0; i < groups.len; 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);
|
||||
for (unsigned int i = 0; i < groups->len; i++) {
|
||||
CmapSubtableLongGroup& group = (*groups)[i];
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
inline void init (hb_face_t *face)
|
||||
|
@ -108,19 +108,19 @@ hb_subset_input_destroy(hb_subset_input_t *subset_input)
|
||||
}
|
||||
|
||||
template<typename TableType>
|
||||
hb_bool_t
|
||||
subset (hb_subset_plan_t *plan, hb_face_t *source, hb_face_t *dest)
|
||||
hb_blob_t *
|
||||
_subset (hb_subset_plan_t *plan, hb_face_t *source)
|
||||
{
|
||||
OT::Sanitizer<TableType> sanitizer;
|
||||
hb_blob_t *table_blob = sanitizer.sanitize (source->reference_table (TableType::tableTag));
|
||||
if (unlikely(!table_blob)) {
|
||||
hb_blob_t *source_blob = sanitizer.sanitize (source->reference_table (TableType::tableTag));
|
||||
if (unlikely(!source_blob)) {
|
||||
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);
|
||||
hb_bool_t result = table->subset(plan, source, dest);
|
||||
const TableType *table = OT::Sanitizer<TableType>::lock_instance (source_blob);
|
||||
hb_blob_t *result = table->subset(plan, source);
|
||||
|
||||
hb_blob_destroy (table_blob);
|
||||
hb_blob_destroy (source_blob);
|
||||
|
||||
hb_tag_t tag = TableType::tableTag;
|
||||
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;
|
||||
|
||||
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 ();
|
||||
if (unlikely (!entry))
|
||||
return false;
|
||||
@ -306,10 +305,12 @@ bool
|
||||
_subset_table (hb_subset_plan_t *plan,
|
||||
hb_face_t *source,
|
||||
hb_tag_t tag,
|
||||
hb_blob_t *table_blob,
|
||||
hb_blob_t *source_blob,
|
||||
hb_face_t *dest)
|
||||
{
|
||||
// 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) {
|
||||
case HB_OT_TAG_glyf:
|
||||
return _subset_glyf (plan, source, dest);
|
||||
@ -320,14 +321,16 @@ _subset_table (hb_subset_plan_t *plan,
|
||||
// SKIP loca, it's handle by glyf
|
||||
return true;
|
||||
case HB_OT_TAG_cmap:
|
||||
// TODO(rsheeter): remove hb_subset_face_add_table
|
||||
// once cmap subsetting works.
|
||||
hb_subset_face_add_table (dest, tag, table_blob);
|
||||
return subset<const OT::cmap> (plan, source, dest);
|
||||
dest_blob = _subset<const OT::cmap> (plan, source);
|
||||
break;
|
||||
default:
|
||||
// Default action, copy table as is.
|
||||
return hb_subset_face_add_table (dest, tag, table_blob);
|
||||
}
|
||||
dest_blob = source_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
Block a user